MyBatis是什么
MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架,它是一个轻量级ORM应用框架。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和java的POJOs(普通的java对象)映射成数据中的记录。它保留了SQL语句并且使SQL语句和应用程序分离。
MyBatis是一个半自动的框架,之所以称它为半自动,是用为它需要手动配置POJO,SQL和映射关系,不像Hibernate只需要提供POJO和映射关系即可。
Mybatis需要提供的映射文件包含了一下三个部分:sql,映射规则,pojo。在Mybatis里面你需要自己编写sql,虽然比Hibernate配置多,但是Mybatis可以配置动态sql,解决了hibernate表名根据时间变化,不同条件下不一样的问题,同时你也可以对sql进行优化,通过配置决定你的sql映射规则,也能支持存储过程,所以对于一些复杂和需要优化性能的sql查询它就更加方便。Mybatis几乎可以做到jdbc所有能做到的事情。
MyBatis什么时候使用
MyBaties的SQL语句是由你编写的,所以Mybaties更有利于SQL的优化。如果项目的数据量比较大,并且效率要求比较高,则建议使用MyBatis框架。
Mybatis如何使用
导入jar包
运用框架首先不必多说的就是要先导入框架所依赖jar包,点击链接下载mybatis的jar包。以为是数据持久层框架所以还需导入访问数据库所依赖的jar包。比如mysql.jar。
创建数据库对象
建立关系型映射之前,我们先需要建立表。1
2
3
4
5
6
7
8CREATE TABLE `students` (
`student_id` int(11) NOT NULL AUTO_INCREMENT,
`student_name` varchar(20) NOT NULL,
`student_sex` char(1) DEFAULT NULL,
`student_birthday` date DEFAULT NULL,
`group_id` varchar(20) DEFAULT NULL,
PRIMARY KEY (`student_id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
建立POJO
建立对象关系型映射之前,当然对象是必不可少的。需要注意的是,写对象属性的时候,属性名中不可以有下划线。并且最好用引用类型,不要用基本数据类型,这样可以提高代码效率。(因为代码比较简单,就不做注释了。)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/**
* @author haozai
* @date 2018年12月5日
*/
package com.aowin.testmybatis.student.pojo;
import java.io.Serializable;
import java.sql.Date;
/**
* 学生基本信息
* @author haozai
* @date 2018年12月5日 上午9:40:49
*/
public class Students implements Serializable {
private Integer studentid;
private String studentname;
private String studentsex;
private Date studentbirthday;
private String groupid;
public Students() {
}
public int getStudentid() {
return studentid;
}
public void setStudentid(Integer studentid) {
this.studentid = studentid;
}
public String getStudentname() {
return studentname;
}
public void setStudentname(String studentname) {
this.studentname = studentname;
}
public String getStudentsex() {
return studentsex;
}
public void setStudentsex(String studentsex) {
this.studentsex = studentsex;
}
public Date getStudentbirthday() {
return studentbirthday;
}
public void setStudentbirthday(Date studentbirthday) {
this.studentbirthday = studentbirthday;
}
public String getGroupid() {
return groupid;
}
public void setGroupid(String groupid) {
this.groupid = groupid;
}
@Override
public String toString() {
return "Students [studentid=" + studentid + ", studentname=" + studentname + ", studentsex=" + studentsex
+ ", studentbirthday=" + studentbirthday + ", groupid=" + groupid + "]";
}
}
创建映射文件
在POJO同目录下创建一个和POJO名相同的xml文件——Students.xml,写映射文件前,需要先导入DTD约束。(因为篇幅比较大,这里我们只介绍DML语句,DQL语句的介绍请点击这里)
DML
1 | <?xml version="1.0" encoding="UTF-8" ?> |
上面的代码只是简单的介绍了一下子标签的属性。真正使用的时候,还需要编写自己所需要的SQL语句。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<?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.aowin.testmybatis.student.pojo.Students" >
<!-- 添加学生信息的执行语句 -->
<insert id="insertstudent" parameterType="com.aowin.testmybatis.student.pojo.Students"
useGeneratedKeys="true" keyProperty="studentid">
<!-- userGeneratedKeys:启动主键 keyProperty:主键属性 -->
<![CDATA[
insert into students (student_name,student_sex,student_birthday,group_id)
values(#{studentname},#{studentsex},#{studentbirthday},#{groupid})
]]>
</insert>
<!-- 修改学生信息 -->
<update id="updatestudent" parameterType="com.aowin.testmybatis.student.pojo.Students">
update students set student_name=#{studentname},student_sex=#{studentsex}
,student_birthday=#{studentbirthday},group_id=#{groupid}
where student_id=#{studentid}
</update>
<!-- 删除学生信息 -->
<delete id="deletestudent" parameterType="int">
delete from students
where student_id=#{studentid}
</delete>
</mapper>
其中将SQL语句用<![CDATA[]]>标签包裹,是为了防止它自己转义(如:>,<等)。在这里也可以编写对应的实体!
这里的parameterType设置成com.aowin.testmybatis.student.pojo.Students。不过,建议大家还是使用typeAlias进行配置吧。唯一需要说明的就是
在数据库里面经常性的会给数据库表设置一个自增长的列作为主键,如果我们操作数据库后希望能够获取这个主键该怎么弄呢?正如上面所述,如果是支持自增长的数据库,如mysql数据库,那么只需要设置useGeneratedKeys和keyProperties属性便可以了,但是对于不支持自增长的数据库(如oracle)该怎么办呢?
mybatis里面在1
2
3
4
5
6
7
8
9
10<selectKey
<!-- selectKey 语句结果应该被设置的目标属性。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 -->
keyProperty="id"
<!-- 结果的类型。MyBatis 通常可以推算出来,但是为了更加确定写上也不会有什么问题。MyBatis 允许任何简单类型用作主键的类型,包括字符串。如果希望作用于多个生成的列,则可以使用一个包含期望属性的 Object 或一个 Map。 -->
resultType="int"
<!-- 这可以被设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它会首先选择主键,设置 keyProperty 然后执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 元素 - 这和像 Oracle 的数据库相似,在插入语句内部可能有嵌入索引调用。 -->
order="BEFORE"
<!-- 与前面相同,MyBatis 支持 STATEMENT,PREPARED 和 CALLABLE 语句的映射类型,分别代表 PreparedStatement 和 CallableStatement 类型。 -->
statementType="PREPARED">
</selectKey>
针对不能使用自增长特性的数据库,可以使用下面的配置来实现相同的功能:1
2
3
4
5
6
7
8
9<insert id="insertUser" parameterType="com.dy.entity.User">
<!-- oracle等不支持id自增长的,可根据其id生成策略,先获取id -->
<selectKey resultType="int" order="BEFORE" keyProperty="id">
select seq_user_id.nextval as id from dual
</selectKey>
insert into students (student_id,student_name,student_sex,student_birthday,group_id)
values(#{id},#{studentname},#{studentsex},#{studentbirthday},#{groupid})
</insert>
接下来我们讲讲查询语句!
动态SQL
写完DML语句,可能很多人就会想到假如我同时要插入多条信息,或者删除多条信息,该怎么写SQL语句呢?别慌,该是动态SQL登场的时候了!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<?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.aowin.testmybatis.student.pojo.Students" >
<!-- 动态SQL -->
<update id="updatestudentdy" parameterType="com.aowin.testmybatis.student.pojo.Students">
update students
<set>
<if test="studentname!=null and studentname!=''">
student_name=#{studentname},
</if>
<if test="studentsex!=null and studentsex!=''">
student_sex=#{studentsex},
</if>
<if test="studentbirthday!=null">
student_birthday=#{studentbirthday},
</if>
<if test="groupid!=null and groupid!=''">
group_id=#{groupid}
</if>
</set>
<where>
student_id=#{studentid}
</where>
</update>
<update id="updatestudentdy2" parameterType="com.aowin.testmybatis.student.pojo.Students">
update students
<trim prefix="set" suffix="where student_id=#{studnetid}" suffixOverrides=",">
<if test="studentname!=null and studentname!=''">
student_name=#{studentname},
</if>
<if test="studentsex!=null and studentsex!=''">
student_sex=#{studentsex},
</if>
<if test="studentbirthday!=null">
student_birthday=#{studentbirthday},
</if>
<if test="groupid!=null and groupid!=''">
group_id=#{groupid}
</if>
</trim>
</update>
</mapper>
这个自己拼接sql语句有些类似,在这里我们介绍一下几个标签:if,choose (when, otherwise),trim (where, set),foreach。
if:if标签一般用于非空验证,如上例,若id为空,if标签里的代码,将不会执行,反之,则会执行。
choose(when,otherwise):相当于switch(case,default) ,如上例,若title 为空,when标签里的代码,将不会执行,默认执行otherwise标签里面的代码。
trim (prefix, suffix,prefixoverride):
- prefix:前缀
- suffix:后缀
- prefixoverride=“AND|OR”:去掉最前面的and或者or;
- suffixoverride=“AND|OR”:去掉最后面的and或者or;
批量处理
1 | <?xml version="1.0" encoding="UTF-8"?> |
这里我们需要介绍一下foreach标签:
foreach:可迭代任何对象(如列表、集合等)和任何的字典或者数组对象传递给foreach作为集合参数,当使用可迭代对象或者数组时,index是当前迭代的次数,item的值是本次迭代获取的元素。当使用字典(或者Map.Entry对象的集合)时,index是键,item是值。
- foreach元素的属性主要有 item,index,collection,open,separator,close。
- collection标签可以填(’list’,’array’,’map’)。
- item表示集合中每一个元素进行迭代时的别名;
- index指 定一个名字,用于表示在迭代过程中,每次迭代到的位置;
- open表示该语句以什么开始,
- separator表示在每次进行迭代之间以什么符号作为分隔符;
- close表示以什么结束。
当有了动态的SQL之后,我们有时间还可能会做批量修改和批量添加的操作。
创建配置文件
所有的配置文件建议都放在resource目录下!
创建DB配置文件
因为要访问数据库需要配置数据库连接的基本信息,我们这里以mysql为例1
2
3
4driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/testmybatis?useUnicode=true&characterEncoding=utf8
username=root
password=123
创建mybatisconfig.xml
配置文件主要分四块:
- 添加数据库、日志配置文件
- 类型别名设定
- 搭建数据库连接池
- 加载映射文件
1 | <?xml version="1.0" encoding="UTF-8"?> |
DAO层的编写
这样我们所有的配置文件都写好了,只需要修改DAO层了。在这里我们就不将所有配置的方法都实现了,例举个别的方法,程序里面会写上比较详细的注释。
程序里面包含了一个工具类:MybatisSqlSessionFactory,在这里就不做详细讲解,它的作用就是得到SqlSession这个核心对象,以及关闭SqlSession。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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115public class StudentDAOImpl implements StudentDAO {
private Logger log = Logger.getLogger(this.getClass());
private SqlSession ss;
public StudentDAOImpl() {
}
@Override
public boolean insertStduent(Students s) {
log.info("调用业务逻辑方法:insertStduent(Students s)");
boolean result = false;
SqlSession ss = MybatisSqlSessionFactory.getSqlSession();
try {
int i = ss.insert("insertstudent", s);
if (i > 0) {
result = true;
log.info("添加学生信息成功" + s);
}
} catch (Exception e) {
log.warn("添加学生信息失败:" + e);
} finally {
if (ss != null)
ss.close();
}
return result;
}
@Override
public boolean deleteStudent(Integer studentid) {
boolean result = false;
SqlSession ss = MybatisSqlSessionFactory.getSqlSession(false);
try {
int i = ss.delete("deletestudent");
if (i > 0) {
ss.commit();
result = true;
log.info("学生信息删除成功!");
} else {
ss.rollback();
log.info("学生信息删除失败!");
}
} catch (Exception e) {
log.warn("学生信息删除失败:" + e);
}
return result;
}
@Override
public boolean updateStudnet(Students s) {
log.info("调用业务逻辑方法:updateStudnet(Students s)");
boolean result = false;
SqlSession ss = MybatisSqlSessionFactory.getSqlSession();
try {
int i = ss.update("updatestudentdy", s);
if (i > 0) {
log.info("修改学生信息成功" + s);
result = true;
}
} catch (Exception e) {
log.info("修改学生信息失败:" + e);
}
MybatisSqlSessionFactory.closeSqlSession();
return result;
}
@Override
public int insertStudents(List<Students> list) {
log.info("调用业务逻辑方法:insertStduent(Students s)");
int i = 0;
SqlSession ss = MybatisSqlSessionFactory.getSqlSession(false);
try {
i = ss.insert("insertstudents", list);
if (i == list.size()) {
ss.commit();
log.info("添加学生信息成功" + list);
} else {
ss.rollback();
log.info("添加学生信息失败,数据回滚!");
}
} catch (Exception e) {
log.warn("添加学生信息失败:" + e);
} finally {
if (ss != null)
ss.close();
}
return i;
}
@Override
public int deleteStudents(List<Integer> list) {
log.info("调用业务逻辑方法:deleteStudents(List<Integer> list)");
int result = 0;
SqlSession ss = MybatisSqlSessionFactory.getSqlSession(false);
try {
int i = ss.delete("deletestudents", list);
if (i == list.size()) {
ss.commit();
result = i;
log.info(i + "行学生信息成功被删除!");
} else {
ss.rollback();
log.info("学生信息删除失败,数据回滚!");
}
} catch (Exception e) {
log.warn("学生信息删除失败:" + e);
}
MybatisSqlSessionFactory.closeSqlSession();
return result;
}
}