MyBatis入门
为什么要使用MyBatis?
MyBatis是一个半自动化的持久化层框架。
- sql和java编码分开,功能边界清晰,一个专注业务、一个专注数据。
- MyBatis 是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架。
- MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。
下载MyBatis
传送门:https://github.com/mybatis/mybatis-3/
(这里使用的是3.4.1版本)
初探MyBatis
第一个例子
使用的IDE为MyEclipse
创建一个数据库和一个数据表,并随意填入数据
1
2
3
4
5
6mysql> create table tbl_employee(
-> id int(11) primary key auto_increment,
-> last_name varchar(255),
-> gender char(1),
-> email varchar(255)
-> );1
2
3
4
5
6
7
8mysql> select * from tbl_employee;
+----+-----------+--------+--------------+
| id | last_name | gender | email |
+----+-----------+--------+--------------+
| 1 | tom | 0 | 13142@qq.com |
| 2 | jerry | 1 | 4243@qq.com |
+----+-----------+--------+--------------+
2 rows in set创建一个javaEE web项目
在项目中定义一个javabean
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// Employee.java
package com.myBatis;
public class Employee {
private Integer id;
private String last_name;
private String email;
private String gender;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getLast_name() {
return last_name;
}
public void setLast_name(String last_name) {
this.last_name = last_name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String toString() {
return "Employee [id=" + id + ", last_name=" + last_name + ", email="
+ email + ", gender=" + gender + "]";
}
}导入相关jar包
在根目录新建conf资源文件夹
在conf文件夹下创建
EmployeeMapper.xml
文件,并添加如下代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
<mapper namespace="com.atguigu.mybatis.EmployeeMapper">
<!-- namespace:命名空间
id: 唯一标识
resultType:返回值类型
-->
<select id="selectEmp" resultType="com.myBatis.Employee">
<!-- tbl_employee为表名 -->
select * from tbl_employee where id = #{id}
</select>
</mapper>在conf文件夹下再创建
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
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<!-- 根据本地数据库进行修改 -->
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<mappers>
<!-- 将写好的sql文件映射到全局文件中 -->
<mapper resource="EmployeeMapper.xml" />
</mappers>
</configuration>新建一个测试类test
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// MybatisTest.java
package com.test;
import java.io.IOException;
import java.io.InputStream;
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 com.myBatis.Employee;
public class MybatisTest {
public void test() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 1.根据xml配置文件(全局配置文件)创建一个SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(inputStream);
// 2.获取sq1Sess1on实例,能直接执行已经映射的sq1语句
SqlSession opensession = sqlSessionFactory.openSession();
try {
// 3.映射到查询命名空间.id的sql语句,传递一个参数1,查询第一个员工并自动封装到javabean中
Employee employee = opensession.selectOne(
"com.atguigu.mybatis.EmployeeMapper.selectEmp", 1);
System.out.println(employee);
} finally {
// 关闭
opensession.close();
}
}
}新建一个servlet模块用于测试
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// TestServlet.java
package com.test;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class TestServlet extends HttpServlet {
/**
* Constructor of the object.
*/
public TestServlet() {
super();
}
/**
* Destruction of the servlet. <br>
*/
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}
/**
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 创建测试类并进行测试
MybatisTest mTest=new MybatisTest();
try {
mTest.test();
} finally {
// TODO: handle exception
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println("<HTML>");
out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");
out.println(" <BODY>");
out.print(" This is ");
out.print(this.getClass());
out.println(", using the GET method");
out.println(" </BODY>");
out.println("</HTML>");
out.flush();
out.close();
}
}
/**
* Initialization of the servlet. <br>
*
* @throws ServletException if an error occurs
*/
public void init() throws ServletException {
// Put your code here
}
}项目整体结构概览
- 浏览器访问
TestServlet
进行测试:http://localhost:8080/HelloMyBatis/servlet/TestServlet - 查看控制台输出
1 | 信息: Reloading Context with name [/HelloMyBatis] is completed |
- 结束
使用接口进行改造(推荐)
创建一个dao接口(com.dao/EmployeeMapper.java)
1
2
3
4
5
6
7
8
9// EmployeeMapper.java
package com.dao;
import com.myBatis.Employee;
public interface EmployeeMapper {
public Employee getEmpById(Integer id);
}在
conf/EmployeeMapper.xml
文件中修改namespace和id1
2
3
4
5
6
7
8
9
10
11
12
13
14<?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.dao.EmployeeMapper">
<!-- namespace:命名空间,这里将命名空间设为接口的全类名
id: 唯一标识,这里将id设为接口的相应函数名
resultType:返回值类型
-->
<select id="getEmpById" resultType="com.myBatis.Employee">
<!-- tbl_employee为表名 -->
select * from tbl_employee where id = #{id}
</select>
</mapper>在
com.test/MybatisTest.java
中新建一个test02方法进行测试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
40package com.test;
import java.io.IOException;
import java.io.InputStream;
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 com.dao.EmployeeMapper;
import com.myBatis.Employee;
public class MybatisTest {
//将获取SqlSessionFactory对象的方法进行封装
public SqlSessionFactory getSqlSessionFactory() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
return sqlSessionFactory;
}
public void test02() throws IOException{
// 1.获取sqlsessionfactory对象
SqlSessionFactory sqlSessionFactory=getSqlSessionFactory();
// 2.获取sqlsession对象
SqlSession openSession=sqlSessionFactory.openSession();
try {
// 3.获取接口的实现类对象
// 会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
EmployeeMapper mapper=openSession.getMapper(EmployeeMapper.class);
// 获取查询结果
Employee employee=mapper.getEmpById(1);
System.out.println(employee);
} finally {
openSession.close();
}
}
}在Servlet中调用该方法即可。
小结
接口式编程
原生:Dao ==> Daoimpl
mybatis: Mapper(Dao) ==> xxMapper.xmlSqlsession代表和据库的一次会话,用完必须关闭
SqlSess1on和 connection一样都是非线程安全,每次使用都应该去获取新的对象。
mapper接口没有实现类,但是 mybatis会为这个接口生一个代理对象.
1
2// 将接口进而xml进行绑定
EmployeeMapper mapper=openSession.getMapper(EmployeeMapper.class);两个重要的置文件
- mybatis的全局配置文件(conf/mybatis-config.xml):包含据库连接泡信息,事务管理器信息等,,,系统运行环境信息
- sql映射文件:保存了每一个sql语句的映射信息。将sql抽取出来。
全局配置文件
第一步
引入XML的dtd约束文件,方便编写XML的时候有提示。
找到之前下载的mybatis.jar包,使用压缩软件打开,找到如下
mybatis-3-mapper.dtd
和mybatis-3-config.dtd
文件,并解压出来

- 在工具栏找到Window->Preferences->搜索XML Catalog,然后选择添加


properties
- mybatis可以使用 properties来引入外 properties配置文件的内容
- resource:引入类路径下的资源
- url:引入网络路径或者路径下的资源
- 创建一个properties文件写入mysql配置信息

在
conf/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
<configuration>
<!-- 引入外部配置文件 -->
<properties resource="dbconfig.properties"></properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<!-- 根据本地数据库进行修改,使用$进行引用 -->
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<mappers>
<!-- 将写好的sql文件映射到全局文件中 -->
<mapper resource="EmployeeMapper.xml" />
</mappers>
</configuration>
settings
这是MyBatis 中极为重要的调整设置,它们会改变MyBatis 的运行时行为。
一个例子
1
2
3
4
5
6<settings>
<!-- 驼峰命名匹配
当javabean中是lastName而mysql中是last_name时也可匹配
-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
typeAliases别名处理器
typeAliases别名处理器:可以为我们的java类型起别名
- type:指定要起别名的类型全类名;默认别名就是类名小写
- alias:指定新的别名
也可以为包下所有类取别名
- package:为某个包下的所有类批量起别名
name指定包名(为当前包以及下面所有的后代包的每一个类都起一个默认别名(类名小写)
- package:为某个包下的所有类批量起别名
举例
1
2
3
4
5<!-- 起别名 -->
<typeAliases>
<typeAlias type="com.myBatis.Employee" alias="emp"/>
<package name="com.myBatis"/>
</typeAliases>
environment
- id:指定当前环境的唯一标识
- transactionManager、和dataSource都必须有
- transactionManager type:JDBC | MANAGED | 自定义
- JDBC:使用了JDBC 的提交和回滚设置,依赖于从数据源得到的连接来管理事务范围。JdbcTransactionFactory
- MANAGED:不提交或回滚一个连接、让容器来管理事务的整个生命周期(比如JEE 应用服务器的上下文)。ManagedTransactionFactory
- 自定义:实现TransactionFactory接口,type=全类名/别名
- dataSource type:UNPOOLED | POOLED | JNDI | 自定义
- UNPOOLED:不使用连接池,UnpooledDataSourceFactory
- POOLED:使用连接池,PooledDataSourceFactory
- JNDI:在EJB 或应用服务器这类容器中查找指定的数据源
- 自定义:实现DataSourceFactory接口,定义数据源的获取方式。
- 实际开发中我们使用Spring管理数据源,并进行事务控制的配置来覆盖上述配置
databaseIdProvider
- MyBatis 可以根据不同的数据库厂商执行不同的语句。
- Type:DB_VENDOR
- 使用MyBatis提供的VendorDatabaseIdProvider解析数据库厂商标识。也可以实现DatabaseIdProvider接口来自定义。
- Property-name:数据库厂商标识
- Property-value:为标识起一个别名,方便SQL语句使用databaseId属性引用
mapper
mapper逐个注册SQL映射文件
也可使用批量注册(这种方式要求SQL映射文件名必须和接口名相同并且在同一目录下)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15mapper
注册配置文件
resource:引用类路径下的sq1映射文件
mybatis/mapper/Employeemapper.xml
ur1:引用网路路径或者路径下的sq1映射文件
file: ///var/mappers/Authormapper.xml
注册接口
cass:引用(注册)接口
1、有sq1映射文件,映射文件名必须和接口同名,并且放在与接口同一目录下
2、没有sq1映射文件,所有的sql都是利用注解写在接口上
<mappers>
<!-- 将写好的sql文件映射到全局文件中 -->
<mapper resource="EmployeeMapper.xml" />
</mappers>
映射文件
映射文件指导着MyBatis如何进行数据库增删改查,有着非常重要的意义。

在第一个例子上进行增删改查
在
com.dao.EmployeeMapper.java
接口中添加增删改查函数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17package com.dao;
import com.myBatis.Employee;
public interface EmployeeMapper {
// 根据id查数据
public Employee getEmpById(Integer id);
// 增加数据
public void addEmp(Employee employee);
// 更新
public void updateEmp(Employee employee);
// 根据id删除数据
public void deleteEmpById(Integer id);
}在
conf/EmployeeMapper.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
35<?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.dao.EmployeeMapper">
<!-- namespace:命名空间,这里将命名空间设为接口的全类名
id: 唯一标识,这里将id设为接口的相应函数名
resultType:返回值类型
-->
<!-- 查询 -->
<select id="getEmpById" resultType="com.myBatis.Employee">
<!-- tbl_employee为表名 -->
select * from tbl_employee where id = #{id}
</select>
<!-- 添加 parameterType可不写 -->
<insert id="addEmp" parameterType="com.myBatis.Employee">
insert into tbl_employee(last_name,gender,email)
values(#{last_name},#{gender},#{email})
</insert>
<!-- 更新 -->
<update id="updateEmp">
update tbl_employee
set last_name=#{last_name},gender=#{gender},email=#{email}
where id=#{id}
</update>
<!-- 删除 -->
<delete id="deleteEmpById">
delete from tbl_employee where id=#{id}
</delete>
</mapper>在
com.myBatis.Employee.java
中加入构造器1
2
3
4
5
6
7
8
9
10
11public Employee() {
super();
}
public Employee(Integer id, String last_name, String email, String gender) {
super();
this.id = id;
this.last_name = last_name;
this.email = email;
this.gender = gender;
}在
com.test.MybatisTest.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
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
97package com.test;
import java.io.IOException;
import java.io.InputStream;
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 com.dao.EmployeeMapper;
import com.myBatis.Employee;
public class MybatisTest {
//将获取SqlSessionFactory对象的方法进行封装
public SqlSessionFactory getSqlSessionFactory() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
return sqlSessionFactory;
}
// 查询
public void test02() throws IOException{
// 1.获取sqlsessionfactory对象
SqlSessionFactory sqlSessionFactory=getSqlSessionFactory();
// 2.获取sqlsession对象
SqlSession openSession=sqlSessionFactory.openSession();
try {
// 3.获取接口的实现类对象
// 会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
EmployeeMapper mapper=openSession.getMapper(EmployeeMapper.class);
// 获取查询结果
Employee employee=mapper.getEmpById(1);
System.out.println(employee);
} finally {
openSession.close();
}
}
// 添加
public void test03() throws IOException {
// 1.获取sqlsessionfactory对象
SqlSessionFactory sqlSessionFactory=getSqlSessionFactory();
// 2.获取sqlsession对象
SqlSession openSession=sqlSessionFactory.openSession();
try{
// 3.获取接口的实现类对象
EmployeeMapper mapper=openSession.getMapper(EmployeeMapper.class);
Employee employee=new Employee(null,"xlh","xlh@qq.com","1");
mapper.addEmp(employee);
// 手动提交数据
openSession.commit();
}finally{
openSession.close();
}
}
// 修改
public void test04() throws IOException {
// 1.获取sqlsessionfactory对象
SqlSessionFactory sqlSessionFactory=getSqlSessionFactory();
// 2.获取sqlsession对象
SqlSession openSession=sqlSessionFactory.openSession();
try{
// 3.获取接口的实现类对象
EmployeeMapper mapper=openSession.getMapper(EmployeeMapper.class);
Employee employee=new Employee(3,"zwx","zwx@qq.com","0");
mapper.updateEmp(employee);
// 手动提交数据
openSession.commit();
}finally{
openSession.close();
}
}
// 删除
public void test05() throws IOException {
// 1.获取sqlsessionfactory对象
SqlSessionFactory sqlSessionFactory=getSqlSessionFactory();
// 2.获取sqlsession对象
SqlSession openSession=sqlSessionFactory.openSession();
try{
// 3.获取接口的实现类对象
EmployeeMapper mapper=openSession.getMapper(EmployeeMapper.class);
mapper.deleteEmpById(4);
// 手动提交数据
openSession.commit();
}finally{
openSession.close();
}
}
}然后在Servlet中进行测试。
另外,可以直接返回Integer/Boolean/Long/void数据类型如下:
1 | //com.dao.EmployeeMapper.java 更新 |
1 | //com.dao.EmployeeMapper.java 更新 |
insert获取自增主键的值
- 采用如下方式插入后,javabean的id为空
1 | <!-- 添加 parameterType可不写 --> |
- 进行修改
1 | <!-- 添加 parameterType可不写 --> |
- 此时再调用addEmp后其javabean的id属性也会变
参数传递
单个参数
- 可以接受基本类型,对象类型,集合类型的值。这种情况MyBatis可直接使用这个参数,不需要经过任何处理。
多个参数
任意多个参数,都会被MyBatis重新包装成一个Map传入。Map的key是param1,param2,0,1…,值就是参数的值。
1
2
3
4
5
6<!-- 查询 -->
<select id="getEmpById" resultType="com.myBatis.Employee">
<!-- tbl_employee为表名 -->
<!-- select * from tbl_employee where id = #{1} and last_name=#{2} -->
select * from tbl_employee where id = #{param1} and last_name=#{param2}
</select>命名参数
在
com.dao.EmployeeMapper.java
接口的函数参数中添加注解1
2// 根据id和name查数据
public Employee getEmpBy(; Integer id, String lastName )在映射文件中可以直接使用名字
1
2
3
4<!-- 查询 -->
<select id="getEmpById" resultType="com.myBatis.Employee">
select * from tbl_employee where id = #{id} and last_name=#{last_name}
</select>
POJO
当这些参数属于我们业务POJO时,我们直接传递POJO,即第一个例子使用的方法
Map
我们也可以封装多个参数为map,直接传递.
1
2
3
4
5
6
7
8
9
10package com.dao;
import java.util.Map;
import com.myBatis.Employee;
public interface EmployeeMapper {
// map查询多参数
public Employee getEmpByMap(Map<String, Object> map);
}1
2
3
4
5<!-- 查询2 -->
<select id="getEmpByMap" resultType="com.myBatis.Employee">
<!-- tbl_employee为表名 -->
select * from tbl_employee where id = #{id} and last_name=#{last_name}
</select>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public void test06() throws IOException {
// 1.获取sqlsessionfactory对象
SqlSessionFactory sqlSessionFactory=getSqlSessionFactory();
// 2.获取sqlsession对象
SqlSession openSession=sqlSessionFactory.openSession(true); // 自动提交
try{
// 3.获取接口的实现类对象
EmployeeMapper mapper=openSession.getMapper(EmployeeMapper.class);
Map<String, Object> map=new HashMap<>();
map.put("id", 1);
map.put("last_name", "tom");
Employee employee= mapper.getEmpByMap(map);
System.out.println(employee);
}finally{
openSession.close();
}
}使用比较多的参数,可以另外编写一个类来实现
特别注意:如果是Collection(List、Set)类型或者是数组也会特殊处理,也是把传入的list或者数组封装在map中.
1 | public Employee getEmpById(List<Integer> ids); |
- #{key}:获取参数的值,预编译到SQL中。安全。
- ${key}:获取参数的值,拼接到SQL中。有SQL注入问题。ORDER BY ${name}参数处理
Select元素
Select元素来定义查询操作。
- Id:唯一标识符
- 用来引用这条语句,需要和接口的方法名一致
- parameterType:参数类型。
- 可以不传,MyBatis会根据TypeHandler自动推断
- resultType:返回值类型。
- 别名或者全类名,如果返回的是集合,定义集合中元素的类型。不能和resultMap同时使用
select返回List
EmployeeMapper.java
1 | package com.dao; |
EmployeeMapper.xml
1 | <!-- 查询3 模糊查询,返回多个数据 List<Employee> getEmpsByLastname(String last_name);--> |
MybatisTest.java
1 | public void test07() throws IOException { |
在Servlet中调用测试
1
2Employee [id=4, last_name=小明, email=xming .com, gender=1]
Employee [id=6, last_name=小红, email=xh .com, gender=0]
select返回Map
EmployeeMapper.java
1
2// 返回一个map
public Map<String, Object> getEmpInMap(Integer id);EmployeeMapper.xml
1
2
3
4
5<!-- 查询3 返回一个map,以键值对显示查询结果 getEmpInMap-->
<select id="getEmpInMap" resultType="map">
<!-- tbl_employee为表名 -->
select * from tbl_employee where id = #{id}
</select>MybatisTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14public void test08() throws IOException {
// 1.获取sqlsessionfactory对象
SqlSessionFactory sqlSessionFactory=getSqlSessionFactory();
// 2.获取sqlsession对象
SqlSession openSession=sqlSessionFactory.openSession(true); // 自动提交
try{
// 3.获取接口的实现类对象
EmployeeMapper mapper=openSession.getMapper(EmployeeMapper.class);
Map<String,Object> map=mapper.getEmpInMap(1);
System.out.println(map);
}finally{
openSession.close();
}
}在Servlet中调用测试
1
{id=1, email=13142 .com, last_name=tom, gender=0}
resultMap
resultMap实现高级结果集映射.
第一个例子
在
com.dao
中新建一个EmployeeMapperPlus.java
1
2
3
4
5
6
7
8package com.dao;
import com.myBatis.Employee;
public interface EmployeeMapperPlus {
// 根据id查数据
public Employee getEmpById(Integer id);
}在conf文件夹下创建一个
EmployeeMapperPlus.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<?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.dao.EmployeeMapperPlus">
<!-- type:自定义规则的java类型
id:唯一标识
-->
<resultMap type="com.myBatis.Employee" id="MyEmp">
<!-- id指定主键列的封装规则
id定义主健,底层有优化
column:指定哪一列
property:指定对应的了javabean属性
-->
<id column="id" property="id" />
<!-- result定义普通列的封装规则 -->
<result column="last_name" property="last_name" />
<result column="gender" property="gender" />
<result column="email" property="email" />
<!-- 其他不指定的列会自动封装 -->
</resultMap>
<select id="getEmpById" resultMap="MyEmp">
select * from tbl_employee where id = #{id}
</select>
</mapper>记得在
conf/mybatis-config.xml
中添加映射文件添加测试代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14public void test09() throws IOException {
// 1.获取sqlsessionfactory对象
SqlSessionFactory sqlSessionFactory=getSqlSessionFactory();
// 2.获取sqlsession对象
SqlSession openSession=sqlSessionFactory.openSession(true); // 自动提交
try{
// 3.获取接口的实现类对象
EmployeeMapperPlus mapper=openSession.getMapper(EmployeeMapperPlus.class);
Employee emp=mapper.getEmpById(1);
System.out.println(emp);
}finally{
openSession.close();
}
}调用servlet进行测试
多表查询(联合查询)
(key为Employee的属性)
多表查询(嵌套结果集)
多表查询(分段查询)
开启延迟加载和属性按需加载
Collection-集合类型&嵌套结果集
Collection-分步查询&延迟加载
扩展-多列值封装map传递
- 分步查询的时候通过column指定,将对应的列的数据传递过去,我们有时需要传递多列数据。使用{key1=column1,key2=column2…}的形式
MyBatis-动态SQL
if
choose
trim
set
foreach
MyBatis-缓存机制
- MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存可以极大的提升查询效率。
- MyBatis系统中默认定义了两级缓存.
- 一级缓存和二级缓存
- 默认情况下,只有一级缓存(SqlSession级别的缓存,也称为本地缓存)开启
- 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
- 为了提高扩展性。MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存
一级缓存体验
- 一级缓存(local cache), 即本地缓存, 作用域默认为sqlSession。当Session flush 或close 后, 该Session 中的所有Cache 将被清空。
- 本地缓存不能被关闭, 但可以调用clearCache() 来清空本地缓存, 或者改变缓存的作用域.
1 | public void test09() throws IOException { |
1 | Employee [id=1, last_name=tom, email=13142 .com, gender=0] |
一级缓存失效的情况
- 不同的SqlSession对应不同的一级缓存
- 同一个SqlSession但是查询条件不同
- 同一个SqlSession两次查询期间执行了任何一次增删改操作
- 同一个SqlSession两次查询期间手动清空了缓存
二级缓存
- 二级缓存(second level cache),全局作用域缓存
- 二级缓存默认不开启,需要手动配置
- MyBatis提供二级缓存的接口以及实现,缓存实现要求POJO实现Serializable接口
- 二级缓存在SqlSession 关闭或提交之后才会生效
- 工作机制
- 一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中
- 如果会话关闭:一级缓存中的数据会被保存到二级缓存中:新的会话查询信息,就可以参照二级缓存
使用
全局配置文件(conf/mybatis-config.xml)中开启二级缓存
1
<setting name="cacheEnabled" value="true"/>
需要使用二级缓存的映射文件(mapper.xml)处使用cache配置缓存
注意:POJO需要实现Serializable接口(即 public class Employee implement Serializable)
二级缓存相关属性
- eviction=“FIFO”:缓存回收策略:
- LRU –最近最少使用的:移除最长时间不被使用的对象。
- FIFO –先进先出:按对象进入缓存的顺序来移除它们。
- SOFT –软引用:移除基于垃圾回收器状态和软引用规则的对象。
- WEAK –弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
- 默认的是LRU。
- flushInterval:刷新间隔,单位毫秒
- 默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
- size:引用数目,正整数
- 代表缓存最多可以存储多少个对象,太大容易导致内存溢出
- readOnly:只读,true/false
- true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势
- false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。
1
2
3<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapper">
<cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024"></cache>
</mapper>- eviction=“FIFO”:缓存回收策略:
二级缓存相关设置
- 全局setting的cacheEnable
- 配置二级缓存的开关。一级缓存一直是打开的。
- select标签的useCache属性
- 配置这个select是否使用二级缓存。一级缓存一直是使用的
- sql标签的flushCache属性
- 增删改默认flushCache=true。sql执行以后,会同时清空一级和二级缓存。查询默认flushCache=false。
- sqlSession.clearCache()
- 只是用来清除一级缓存。
- 当在某一个作用域(一级缓存Session/二级缓存Namespaces) 进行了C/U/D 操作后,默认该作用域下所有select 中的缓存将被clear。
- 全局setting的cacheEnable
图解
