MyBatis专题(三)-整合DAO

MyBatis作为持久层框架,必然与项目分层中的DAO层相关。本次要介绍的内容是如何把MyBatis引入到项目的DAO层并整合业务层,将分别介绍三种引入方式。本次不引入Spring之类的框架,后期再介绍关于MyBatis和Spring的内容。

DAO即数据访问对象(Data Access Object),其它语言(比如C#)中可能被称作DAL(Data Access Layer),即数据访问层。在Java多层架构中充当持久层的角色,负责与数据库交互。DAO旨在封装数据库操作逻辑,仅对外暴露上层操作接口,屏蔽了具体底层的数据库访问逻辑(不公开)。

以下两种方式在参数和结果集上都使用对象映射的方式,所以需要有一个实体类与数据库字段关联,数据库的表跟上一章节一样,仅使用user表,这里暂不涉及多表关联。新建一个User实体类,类属性尽量与数据库字段一致,这样可以方便MyBatis进行映射,当然,您也可以用字段别名来解决。

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
package com.oopsguy.mybatistopic.entity;

public class User {

private Integer id;
private String username;
private String password;

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}

编辑主配置文件mybatis-config.xml,完善数据库相关信息。

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
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!--开启日志并使用标准输入输出日志实现-->
<setting name="logImpl" value="STDOUT_LOGGING" />
<!--启用主键获取,部分数据库不支持-->
<setting name="useGeneratedKeys" value="true" />
</settings>

<environments default="development">
<environment id="development">
<!--事务有JDBC处理-->
<transactionManager type="JDBC"/>
<!--使用连接池管理数据库连接-->
<dataSource type="POOLED">
<!--数据库驱动-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--JDBC连接字符串-->
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis_topic_chapter3"/>
<!--数据库用户名-->
<property name="username" value="root"/>
<!--数据库密码-->
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>

<!--需要加载的mapper映射文件-->
<mappers>
<!--mapper文件-->
</mappers>
</configuration>

以上配置文件开启了标准流日志输出,并开启了获取主键生成,这个并不是所有数据库都支持,开启这项配置之后,您可以在向数据库插入数据之后获取到数据库生成的主键值。

我们预先定义一套DAO的接口:

1
2
3
4
5
- deleteById(Integer id) 通过id删除用户
- getById(Integer id) 通过id获取单个用户
- findAll() 获取全部用户
- update(User user) 更新用户
- insert(User user) 添加用户

这些接口比较简单,只是基本的CURD,关于动态SQL的组装下一章会讲到。

仅映射文件方式

使用mapper文件作为DAO接口是第一种方式,跟之前介绍的配置方式一样,在mapper文件中定义好SQL操作片段,我们可以把每一个接口的操作定义为一个操作标签,把整个mapper看作是一个DAO类。

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
<?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">
<mapper namespace="UserDao">

<!--添加用户-->
<insert id="insert" useGeneratedKeys="true" keyProperty="id" parameterType="com.oopsguy.mybatistopic.entity.User">
INSERT INTO user(username, password) VALUES (#{username}, #{password})
</insert>

<!--通过id获取用户-->
<select id="getById" resultType="com.oopsguy.mybatistopic.entity.User">
SELECT id, username, password FROM user WHERE id=#{id}
</select>

<!--获取所有用户-->
<select id="findAll" resultType="com.oopsguy.mybatistopic.entity.User">
SELECT id, username, password FROM user
</select>

<!--更新用户信息-->
<update id="update" parameterType="com.oopsguy.mybatistopic.entity.User">
UPDATE user set username=#{username}, password=#{password} WHERE id=#{id}
</update>

<!--根据id删除用户-->
<delete id="deleteById">
DELETE FROM user WHERE id=#{id}
</delete>

</mapper>

我们把这个mapper的namespace命名UserDao,即方便表示这是一个操作user的DAO映射文件。不过需要注意的是,在大项目中这样的明明层次还不够深,容易引起命名空间的冲突,一般都会以包名的格式命名,例如:com.oopsguy.dao.UserDao

在mapper文件中,可以观察到,id为insert的insert操作标签中定义了useGeneratedKeys="true" keyProperty="id"属性,这表示启用获取自增主键,并把主键的值赋值到id属性中。进一步讲,当一个user实体的信息被成功插入到数据库中,由于表定义中声明id为自增主键,数据库对id进行自增操作后,MyBatis获取到主键的值,然后赋值给user实体的id属性。使用useGeneratedKeys="true",需要在主配置文件中启用useGeneratedKeys配置。

把此mapper定义到主配置文件mybatis-config.xml加载:

1
2
3
<mappers>
<mapper resource="mapper/UserMapper.xml" />
</mappers>

接下来我们定义Service层来调用DAO方法,在通过一个main方法来测试DAO,这里就不使用单元测试了。

定义Service接口Service.java

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
package com.oopsguy.mybatistopic.service;

import com.oopsguy.mybatistopic.entity.User;

import java.util.List;

/**
* 业务层接口
*/
public interface Service {

/**
* 添加用户
* @param user 用户实体对象
*/
void insert(User user);

/**
* 通过id获取用户实体
* @param id 用户id
* @return 用户实体
*/
User getById(Integer id);

/**
* 获取所有用户实体
* @return 所有用户实体
*/
List<User> findAll();

/**
* 跟新用户信息
* @param user 用户实体对象
*/
void update(User user);

/**
* 根据用户id删除用户
* @param id 用户id
*/
void deleteById(Integer id);
}

由于官方推荐把SqlSessionFactory作为单例使用,不需要每次都实例化浪费资源,我们定义一个获取单例的工具类MyBatisUtil.java

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
package com.oopsguy.mybatistopic.util;


import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;

/**
* MyBatis工具类
*/
public class MyBatisUtil {

private static final String CONFIG_FILE = "mybatis-config.xml";

private static SqlSessionFactory sqlSessionFactory = null;

private MyBatisUtil() {
}

/**
* 获取SqlSessionFactory单例
*
* @return SqlSessionFactory实例
*/
public static SqlSessionFactory getSqlSessionFactory() {
if (sqlSessionFactory == null) {
synchronized (MyBatisUtil.class) {
if (sqlSessionFactory == null) {
try {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(CONFIG_FILE));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

return sqlSessionFactory;
}

}

以上的单例写法使用了双检(Double-Check)机制。之后使用到Sql’SessionFactory的地方,可以直接通过该类获取。

之后新建一个实现了Service接口的具体业务类MapperServiceImpl.java

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
package com.oopsguy.mybatistopic.service.impl;

import com.oopsguy.mybatistopic.entity.User;
import com.oopsguy.mybatistopic.service.Service;
import com.oopsguy.mybatistopic.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import java.util.List;

/**
* 使用了mapper定义的DAO
*/
public class MapperService implements Service {

private SqlSessionFactory sessionFactory = null;

public MapperService() {
this.sessionFactory = MyBatisUtil.getSqlSessionFactory();
}

public void insert(User user) {
SqlSession sqlSession = this.sessionFactory.openSession();
sqlSession.insert("UserDao.insert", user);
sqlSession.commit();
sqlSession.close();
}

public User getById(Integer id) {
SqlSession sqlSession = this.sessionFactory.openSession();
User user = sqlSession.selectOne("UserDao.getById", id);
sqlSession.close();

return user;
}

public List<User> findAll() {
SqlSession session = this.sessionFactory.openSession();
List<User> users = session.selectList("UserDao.findAll");
session.close();

return users;
}

public void update(User user) {
SqlSession session = this.sessionFactory.openSession();
session.update("UserDao.update", user);
session.commit();
session.close();
}

public void deleteById(Integer id) {
SqlSession session = this.sessionFactory.openSession();
session.delete("UserDao.deleteById", id);
session.commit();
session.close();
}

}

因为SqlSesison是轻量级、线程不安全的类,官方推荐应该在方法级别等小范围使用,使用完之后立刻销毁。在每一个具体的实现方法中,我们通过SqlSessionFactory来创建SqlSession,在操作数据的添加和更新时,需要提交事务,否则操作将不会生效,操作完成立马关闭SqlSession。

最后一个主类(MapperDaoMain.java)来运行示例代码:

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
package com.oopsguy.mybatistopic;

import com.oopsguy.mybatistopic.entity.User;
import com.oopsguy.mybatistopic.service.Service;
import com.oopsguy.mybatistopic.service.impl.MapperService;

import java.util.List;

/**
* 使用mapper定义的DAO
*/
public class MapperDaoMain {

public static void main(String[] args) {
Service service = new MapperService();
User user = new User();

//添加
user.setPassword("password11111");
user.setUsername("username11111");
service.insert(user);
System.out.

user.setUsername("username2222");
user.setPassword("password2222");
service.insert(user);

//修改
user.setUsername("Oopsguy");
service.update(user);

//获取单个
user = service.getById(1);
System.out.println(user);

//获取全部
List<User> users = service.findAll();
System.out.println(users);

//删除
service.deleteById(1);
users = service.findAll();
System.out.println(users);
}

}

以上代码实例化出一个MapperServiceImpl实例,添加了两条user记录,这两次添加都有输出语句输出实体信息,添加之后,我们发现之前没有为user设置id,但输出之后id是带有特定值的,说明MyBatis获取了数据库自增主键的值设置给了id属性。之后修改最后一条user的用户名为Oopsguy,并获取id为1的记录,再获取全部记录输出,可以看到数据的内容打印出了,是有两条记录的,最后删除id为1的记录并输出全部记录,发现只剩下一条记录。

具体的输出信息(省略了其它不必要的信息):

1
2
3
4
5
6
7
8
9
10
11
User{id=1, username='username11111', password='password11111'}
........
User{id=2, username='username2222', password='password2222'}
........
User{id=1, username='username11111', password='password11111'}
........
[User{id=1, username='username11111', password='password11111'}, User{id=2, username='Oopsguy', password='password2222'}]
.......
[User{id=2, username='Oopsguy', password='password2222'}]

Process finished with exit code 0

使用接口与映射文件方式

通过上述示例,您会发现,我们在Service中调用DAO的方法都是以字符串的形式指定,这非常糟糕,因为只要写错一个字符,程序运行就会出错,而且在编写代码时,即使写错了标识,IDE也不会提示。为了能在代码编写期间保证每一个DAO接口的引用都是正确的,我们可以使用mapper文件和interface的方式来组合配置,在使用DAO的时候只需使用interface。

这次需要新建一个DAO接口(UserDao.java),这个接口与我们之前定义的差不多:

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
package com.oopsguy.mybatistopic.dao;

import com.oopsguy.mybatistopic.entity.User;

import java.util.List;

/**
* 用户数据访问对象接口
*/
public interface UserDao {

/**
* 添加用户
*
* @param user 用户实体对象
*/
void insert(User user);

/**
* 通过id获取用户实体
*
* @param id 用户id
* @return 用户实体
*/
User getById(Integer id);

/**
* 获取所有用户实体
*
* @return 所有用户实体
*/
List<User> findAll();

/**
* 跟新用户信息
*
* @param user 用户实体对象
*/
void update(User user);

/**
* 根据用户id删除用户
*
* @param id 用户id
*/
void deleteById(Integer id);
}

添加一个对应接口的mapper文件(UserInterfaceMapper.xml):

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
<?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">
<mapper namespace="com.oopsguy.mybatistopic.dao.UserDao">

<!--添加用户-->
<insert id="insert" useGeneratedKeys="true" keyProperty="id" parameterType="com.oopsguy.mybatistopic.entity.User">
INSERT INTO user(username, password) VALUES (#{username}, #{password})
</insert>

<!--通过id获取用户-->
<select id="getById" resultType="com.oopsguy.mybatistopic.entity.User">
SELECT id, username, password FROM user WHERE id=#{id}
</select>

<!--获取所有用户-->
<select id="findAll" resultType="com.oopsguy.mybatistopic.entity.User">
SELECT id, username, password FROM user
</select>

<!--更新用户信息-->
<update id="update" parameterType="com.oopsguy.mybatistopic.entity.User">
UPDATE user set username=#{username}, password=#{password} WHERE id=#{id}
</update>

<!--根据id删除用户-->
<delete id="deleteById">
DELETE FROM user WHERE id=#{id}
</delete>

</mapper>

与之前有点区别的是,mapper的命名空间改成了与DAO接口的全名(包名+接口名)一致。

记得把mapper文件加入到主配置文件mybatis-config.xml<mappers>中:

1
2
3
4
<mappers>
<mapper resource="mapper/UserMapper.xml" />
<mapper resource="mapper/UserInterfaceMapper.xml"/>
</mappers>

具体的Service类(InterfaceMapperService.java):

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
package com.oopsguy.mybatistopic.service.impl;

import com.oopsguy.mybatistopic.dao.UserDao;
import com.oopsguy.mybatistopic.entity.User;
import com.oopsguy.mybatistopic.service.Service;
import com.oopsguy.mybatistopic.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import java.util.List;

/**
* 使用mapper和interface的DAO
*/
public class InterfaceMapperService implements Service {

private SqlSessionFactory sessionFactory = null;
UserDao userDao = null;

public InterfaceMapperService() {
this.sessionFactory = MyBatisUtil.getSqlSessionFactory();
}


public void insert(User user) {
SqlSession session = this.sessionFactory.openSession();
userDao = session.getMapper(UserDao.class);
userDao.insert(user);
session.commit();
session.close();
}

public User getById(Integer id) {
SqlSession session = this.sessionFactory.openSession();
userDao = session.getMapper(UserDao.class);
User user = userDao.getById(id);
session.close();

return user;
}

public List<User> findAll() {
SqlSession session = this.sessionFactory.openSession();
userDao = session.getMapper(UserDao.class);
List<User> users = userDao.findAll();
session.close();

return users;
}

public void update(User user) {
SqlSession session = this.sessionFactory.openSession();
userDao = session.getMapper(UserDao.class);
userDao.update(user);
session.commit();
session.close();
}

public void deleteById(Integer id) {
SqlSession session = this.sessionFactory.openSession();
userDao = session.getMapper(UserDao.class);
userDao.deleteById(id);
session.commit();
session.close();
}
}

从上面的Service中可以看到,调用DAO的接口已经改成了新的方式:session.getMapper(DAO.class),传入一个DAO接口,MyBatis找到命名空间与此接口全名相同的mapper,它接口的方法与mapper定义的操作的id绑定。所以,您应该尽可能保持命名空间和操作id与DAO接口的全程和方法名一致。通过这种方式,我们像写错DAO接口的名称都难了,哈哈。

之后测试功能,主类(InterfaceMapperMain.java)的代码:

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
package com.oopsguy.mybatistopic;

import com.oopsguy.mybatistopic.entity.User;
import com.oopsguy.mybatistopic.service.Service;
import com.oopsguy.mybatistopic.service.impl.InterfaceMapperService;

import java.util.List;

public class InterfaceMapperMain {

public static void main(String[] args) {
Service service = new InterfaceMapperService();
User user = new User();

user.setUsername("Hello");
user.setPassword("World");
service.insert(user);
System.out.println(user);

user.setPassword("WorldPassword");
service.update(user);
user = service.getById(4);

List<User> users = service.findAll();
System.out.println(users);

service.deleteById(4);
users = service.findAll();
System.out.println(users);
}

}

运行结果:

1
2
3
4
5
6
7
User{id=4, username='Hello', password='World'}
......
[User{id=2, username='Oopsguy', password='password2222'}, User{id=3, username='Hello', password='World'}, User{id=4, username='Hello', password='WorldPassword'}]
......
[User{id=2, username='Oopsguy', password='password2222'}, User{id=3, username='Hello', password='World'}]

Process finished with exit code 0

效果完全一样,但是比之前的更加完美。

接口与注解方式

可能有些人会觉得为什么一定要写mapper文件,我不想写XML,可不可以不写。答案是可以的!MyBatis还提供了注解定义方式,您只需要定义DAO接口,之后在DAO接口上使用注解定义具体的SQL语句和属性配置,这完全脱离mapper文件,不需要额外的配置。

流程依旧,新建一个使用注解的DAO接口文件(AnnotationDao.java):

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
package com.oopsguy.mybatistopic.dao;

import com.oopsguy.mybatistopic.entity.User;
import org.apache.ibatis.annotations.*;

import java.util.List;

public interface AnnotationDao {
/**
* 添加用户
*
* @param user 用户实体对象
*/
@Options(useGeneratedKeys = true, keyColumn = "id")
@Insert("INSERT INTO user (username, password) VALUES (#{username}, #{password})")
void insert(User user);

/**
* 通过id获取用户实体
*
* @param id 用户id
* @return 用户实体
*/
@Select("SELECT id, username, password FROM user WHERE id=#{id}")
User getById(@Param("id") Integer id);

/**
* 获取所有用户实体
*
* @return 所有用户实体
*/
@Select("SELECT id, username, password FROM user")
List<User> findAll();

/**
* 跟新用户信息
*
* @param user 用户实体对象
*/
@Update("UPDATE user SET username=#{username}, password=#{password} WHERE id=#{id}")
void update(User user);

/**
* 根据用户id删除用户
*
* @param id 用户id
*/
@Delete("DELETE FROM user WHERE id=#{id}")
void deleteById(Integer id);
}

先来简单介绍一下,在这个DAO中,我们使用了MyBatis提供的注解,它们代表这XML中的特定的操作标签:

  • @Select - <select>
  • @Update - <update>
  • @Insert - <insert>
  • @Delete - <delete>

这些注解中需要传入SQL语句。

在使用@Insert的接口上,我们使用了@Options注解,这个注解指定一些属性参数,类似与XML上的属性定义,这里定义了主键获取。在getById方法中,使用到了一个@Param注解,这个注解指明了当前参数对应SQL语句中的占位符名称,当然,这个注解在此处是多余的,因为只有一个参数,无需指定。但是当方法中有多个参数,比如findPage(Integer offset, Integer size, String where),这里面有三个参数定义,并且与SQL中的占位符名称不一致时,可以使用@Param注解指定参数名称。

注意,使用注解接口的方式,跟mapper一样,需要配置到主配置文件mybatis-config.xml中:

1
2
3
<mappers>
<mapper class="com.oopsguy.mybatistopic.dao.AnnotationDao" />
</mappers>

跟基于XML的mapper文件不同,注解接口使用<mapper>标签的class属性指定接口的全名。

完成DAO之后就是Service(AnnotationService.java)的编写,不过没什么大的变化:

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
package com.oopsguy.mybatistopic.service.impl;

import com.oopsguy.mybatistopic.dao.AnnotationDao;
import com.oopsguy.mybatistopic.dao.UserDao;
import com.oopsguy.mybatistopic.entity.User;
import com.oopsguy.mybatistopic.service.Service;
import com.oopsguy.mybatistopic.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import java.util.List;

/**
* 使用Annotation的DAO
*/
public class AnnotationService implements Service {

private SqlSessionFactory sessionFactory = null;
AnnotationDao userDao = null;

public AnnotationService() {
this.sessionFactory = MyBatisUtil.getSqlSessionFactory();
}


public void insert(User user) {
SqlSession session = this.sessionFactory.openSession();
userDao = session.getMapper(AnnotationDao.class);
userDao.insert(user);
session.commit();
session.close();
}

public User getById(Integer id) {
SqlSession session = this.sessionFactory.openSession();
userDao = session.getMapper(AnnotationDao.class);
User user = userDao.getById(id);
session.close();

return user;
}

public List<User> findAll() {
SqlSession session = this.sessionFactory.openSession();
userDao = session.getMapper(AnnotationDao.class);
List<User> users = userDao.findAll();
session.close();

return users;
}

public void update(User user) {
SqlSession session = this.sessionFactory.openSession();
userDao = session.getMapper(AnnotationDao.class);
userDao.update(user);
session.commit();
session.close();
}

public void deleteById(Integer id) {
SqlSession session = this.sessionFactory.openSession();
userDao = session.getMapper(AnnotationDao.class);
userDao.deleteById(id);
session.commit();
session.close();
}
}

用法跟第二种一样,使用SqlSession的getMapper方法获取映射类。

声明测试主类(AnnotationMain.java):

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
package com.oopsguy.mybatistopic;

import com.oopsguy.mybatistopic.entity.User;
import com.oopsguy.mybatistopic.service.Service;
import com.oopsguy.mybatistopic.service.impl.AnnotationService;

import java.util.List;

/**
* 使用Annotation的DAO
*/
public class AnnotationMain {

public static void main(String[] args) {
Service service = new AnnotationService();
User user = new User();

user.setUsername("My");
user.setPassword("Batis");
service.insert(user);
System.out.println(user);

user.setPassword("HelloMyBatis");
service.update(user);
user = service.getById(5);

List<User> users = service.findAll();
System.out.println(users);

service.deleteById(5);
users = service.findAll();
System.out.println(users);
}

}

运行结果:

1
2
3
4
5
6
7
User{id=5, username='My', password='Batis'}
......
[User{id=2, username='Oopsguy', password='password2222'}, User{id=3, username='Hello', password='World'}, User{id=5, username='My', password='HelloMyBatis'}]
......
[User{id=2, username='Oopsguy', password='password2222'}, User{id=3, username='Hello', password='World'}]

Process finished with exit code 0

符合预期结果。

总结

本内容介绍了利用MyBatis作为DAO层的三种方式:1、仅映射文件;2、接口与和映射文件结合;3、接口注解方式。这三种当中第二种方式用的比较多,接口方便调用,排字符串形式拼写导致错误的问题,SQL语句配置在XML中,方便维护与扩展。第一种的接口基于字符串引用,容易发生错误,第三种使用注解,SQL语句需要写在注解中,如果SQL语句过长,将导致代码臃肿,难以维护,而且大量的SQL硬编码,修改工作巨大。此次示例的SQL比较简单,没有复杂的映射与动态语句,下一部分内容将介绍动态SQL。