您的位置:首页 > 移动开发

原始dao和Mapper动态代理的开放方式---Mybatis学习笔记(六)

2017-08-16 21:22 531 查看


1.原始Dao开发方式

原始Dao开发方法需要程序员编写Dao接口和Dao实现类。 
1.映射文件:(user.xml)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace :命名空间,用于隔离sql语句,后面会讲另一层非常重要的作用。 -->
<mapper namespace="test">

<!-- 根据Id获取用户信息 ,返回一条数据-->
<!-- 通过<select>进行数据库查询
id:标识映射文件中的sql
将sql语句封装到mappedStatement对象中,所以将id称为statement的id
parameterType:指定输入参数的类型
#{}:表示一个占位符
#{id}:其中的id表示接收输入的参数,参数的名称就是id,如果输入参数为简单类型,#{}中的参数名可以任意,可以value也可以其它名称。
resultType:指定sql输出结果的所映射的java对象类型。select指定resultType表示将单条记录映射成的java对象。
-->
<select id="findUserById" parameterType="int" resultType="com.huihui.pojo.User">
select * from user where id=#{id}
</select>
<!-- 自定义条件查询用户列表,可能返回多条 -->
<!--
${}:表示拼接sql串,将接收到的参数的内容不加任何修饰拼接到sql中。
使用${}拼接sql,可能引起sql注入
${value}:接收输入参数的内容,如果传入的类型是简单类型,${}中只能使用value
-->
<select id="findUserByUsername" parameterType="java.lang.String" resultType="com.huihui.pojo.User">
select * from user where username like '%${value}%'
</select>

<!-- 添加用户 -->
<!--
parameterType:指定输入参数类型为pojo
#{}中指定pojo的属性名,接收到pojo对象的属性值
-->
<insert id="insertUser" parameterType="com.huihui.pojo.User" >
insert into user(username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})
<!-- selectKey将主键返回,需要再返回 -->
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select LAST_INSERT_ID()
</selectKey>
</insert>

<!-- 删除用户 -->
<!-- 根据id删除用户,需要输入id值 -->
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id = #{id}
</delete>

<!-- 更新用户 -->
<!-- 根据id更新用户,需要传入用户的id和用户的更新信息(也就是传入User对象,但是user对象中的id必须存在) -->
<update id="updateUser" parameterType="com.huihui.pojo.User">
update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
</update>
</mapper>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

2.Dao接口:
package com.huihui.dao;

import java.util.List;

import com.huihui.pojo.User;

public interface UserDao {

//根据id查询用户信息
public User findUserById(int id) throws Exception;

//根据用户的名称查询用户的信息
public List<User> findUserByName(String name) throws Exception;

//添加用户信息
public void insertUser(User user) throws Exception;

//删除用户信息
public void deleteUser(int id) throws Exception;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

3.Dao接口实现类:
package com.huihui.dao;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import com.huihui.pojo.User;

public class UserDaoImpl implements UserDao{

//需要向dao实现类中注入SqlSessionFactory
//这里通过构造方法注入
private SqlSessionFactory sqlSessionFactory;

public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}

@Override
public User findUserById(int id) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("test.findUserById", id);
//释放资源
sqlSession.close();
return user;
}

@Override
public void insertUser(User user) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.insert("test.insertUser", user);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}

@Override
public void deleteUser(int id) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.delete("test.deleteUser", id);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}

@Override
public List<User> findUserByName(String name) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.selectList("test.findUserByUsername", name);
//释放资源
sqlSession.close();
return null;
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

4.加载user.xml文件 

修改SqlMapConfig.xml文件:
<!-- 加载映射文件 -->
<mappers>
<mapper resource="sqlmap/user.xml"/>
</mappers>
1
2
3
4
5
1
2
3
4
5

5.测试代码:
public class UserDaoImplTest {

private SqlSessionFactory sqlSessionFactory;

@Before
//此方法是运行下面的测试用例的方法之前执行的
public void setUp() throws Exception{
//创建sqlSessionFactory
//mybatis配置文件路径
String resource = "SqlMapConfig.xml";
//得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建会话工厂,传入mybatis的配置文件信息
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindUserById() throws Exception{
//创建一个userDao的对象
UserDao userDao = new UserDaoImpl(sqlSessionFactory);
//调用UserDao方法
User user = userDao.findUserById(1);
System.out.println(user);
}
@Test
public void testFindUserByName() throws Exception{
//创建一个userDao对象
UserDao userDao = new UserDaoImpl(sqlSessionFactory);
//调用UserDao方法
List<User> list = userDao.findUserByName("张");
System.out.println(list.size());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32


分析原始Dao开发方式存在的问题:

原始Dao开发中存在以下问题:
Dao方法体存在重复代码:通过SqlSessionFactory创建SqlSession,调用SqlSession的数据库操作方法
调用sqlSession的数据库操作方法需要指定statement的id,这里存在硬编码,不利于开发维护。
调用sqlsession方法时传入的变量,由于sqlsession方法使用泛型,即使变量类型传入错误,在编译阶段也不报错,不利于程序员开发。


2.mapper动态代理的方法

实现原理 

Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。

Mapper接口开发需要遵循以下规范:
Mapper.xml文件中的namespace与mapper接口的类路径相同。
Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

只有遵循以上规范,mybatis才可以自动生成mapper接口的实现类代理对象。 

其实以上的规范主要为了相对于dao实现类中的以下方法进行了自动生成:
User user = sqlSession.selectOne("test.findUserById", id);

sqlSession.insert("test.insertUser", user);

sqlSession.delete("test.deleteUser", id);

sqlSession.selectList("test.findUserByUsername", name);
...
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8

1.映射文件(UserMapper.xml文件): 

定义mapper映射文件UserMapper.xml(内容同User.xml一样),需要修改namespace的值为UserMapper接口路径。将UserMapper.xml放在classpath下mapper目录下。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace :命名空间,用于隔离sql语句,后面会讲另一层非常重要的作用(需要修改namespace的值为UserMapper接口路径)。 -->
<mapper namespace="com.huihui.mapper.UserMapper">

<!-- 根据Id获取用户信息 ,返回一条数据-->
<!-- 通过<select>进行数据库查询
id:标识映射文件中的sql
将sql语句封装到mappedStatement对象中,所以将id称为statement的id
parameterType:指定输入参数的类型
#{}:表示一个占位符
#{id}:其中的id表示接收输入的参数,参数的名称就是id,如果输入参数为简单类型,#{}中的参数名可以任意,可以value也可以其它名称。
resultType:指定sql输出结果的所映射的java对象类型。select指定resultType表示将单条记录映射成的java对象。
-->
<select id="findUserById" parameterType="java.lang.Integer" resultType="com.huihui.pojo.User">
select * from user where id=#{id}
</select>
<!-- 自定义条件查询用户列表,可能返回多条 -->
<!--
${}:表示拼接sql串,将接收到的参数的内容不加任何修饰拼接到sql中。
使用${}拼接sql,可能引起sql注入
${value}:接收输入参数的内容,如果传入的类型是简单类型,${}中只能使用value
-->
<select id="findUserByUsername" parameterType="java.lang.String" resultType="com.huihui.pojo.User">
select * from user where username like '%${value}%'
</select>

<!-- 添加用户 -->
<!--
parameterType:指定输入参数类型为pojo
#{}中指定pojo的属性名,接收到pojo对象的属性值
-->
<insert id="insertUser" parameterType="com.huihui.pojo.User" >
insert into user(username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})
<!-- selectKey将主键返回,需要再返回 -->
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select LAST_INSERT_ID()
</selectKey>
</insert>

<!-- 删除用户 -->
<!-- 根据id删除用户,需要输入id值 -->
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id = #{id}
</delete>

<!-- 更新用户 -->
<!-- 根据id更新用户,需要传入用户的id和用户的更新信息(也就是传入User对象,但是user对象中的id必须存在) -->
<update id="updateUser" parameterType="com.huihui.pojo.User">
update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
</update>
</mapper>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

2.接口(UserMapper.Java文件) 

接口定义有如下特点:
Mapper接口方法名和Mapper.xml中定义的statement的id相同
Mapper接口方法的输入参数类型和mapper.xml中定义的statement的parameterType的类型相同
Mapper接口方法的输出参数类型和mapper.xml中定义的statement的resultType的类型相同
package com.huihui.mapper;

import java.util.List;

import com.huihui.pojo.User;

/**
* mapper接口,相当于dao接口
* 用户管理
* @author 62347
*
*/
public interface UserMapper {

//根据id查询用户信息
public User findUserById(int id) throws Exception;

//根据用户名列查询用户列表
public List<User> findUserByUsername(String name) throws Exception;

//添加用户信息
public void insertUser(User user) throws Exception;

//删除用户信息
public void deleteUser(int id) throws Exception;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

3.加载UserMapper.xml文件
<!-- 加载映射文件 -->
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
1
2
3
4
5
1
2
3
4
5

4.测试代码:
package com.huihui.mapper;

import java.io.InputStream;
import java.util.Date;
import java.util.List;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

import com.huihui.pojo.User;

public class UserMapperTest {

private SqlSessionFactory sqlSessionFactory;

@Before
//此方法是运行下面的测试用例的方法之前执行的
public void setUp() throws Exception{
//创建sqlSessionFactory
//mybatis配置文件路径
String resource = "SqlMapConfig.xml";
//得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建会话工厂,传入mybatis的配置文件信息
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}

@Test
public void testFindUserById() throws Exception {
//通过会话工厂得到会话
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建UserMapper对象,mybatis自动生成mapper代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

User user = userMapper.findUserById(30);
System.out.println(user);

sqlSession.close();
}

@Test
public void testFindUserByName() throws Exception {
//通过会话工厂得到会话
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建UserMapper对象,mybatis自动生成mapper代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

List<User> list = userMapper.findUserByUsername("张");
System.out.println(list.size());

sqlSession.close();
}

@Test
public void testInsertUser() throws Exception {
//通过会话工厂得到会话
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建UserMapper对象,mybatis自动生成mapper代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

User user = new User();
user.setSex("2");
user.setBirthday(new Date());
user.setAddress("北京丰台");
user.setUsername("哒哒哒");

userMapper.insertUser(user);

sqlSession.commit();//提交事务
sqlSession.close();
}

@Test
public void testDeleteUser() throws Exception {
//通过会话工厂得到会话
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建UserMapper对象,mybatis自动生成mapper代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

userMapper.deleteUser(30);

sqlSession.commit();//提交事务
sqlSession.close();
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

重点说明:
selectOne和selectList 

动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。
mapper接口输入参数只能有一个,是否不利于系统扩展维护? 

系统框架中,dao层的代码是被业务层公用的。即使mapper接口中只有一个参数,也可以使用包装类型的pojo满足不同的业务方法的需求。 

注意:持久层中方法的参数可以是包装类型(eg:map,…..),但是service方法中不建议使用包装类型(原因:不利于业务层的可扩展)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  mybatis