概述
文章目录
- MyBatis
- 1. 入门使用
- 1.1 导入相关 Maven 依赖
- 1.2 创建并配置核心文件
- 1.3 编写 MyBatis 工具类
- 1.4 编写实体类
- 1.5 编写实体类对应的 Mapper 接口
- 1.6 编写 Mapper 配置文件
- 1.7 测试
- 1.8 一些可能的问题
- 2. CRUD
- 2.1 Select
- 2.2 Update、Delete、Insert —(增删改需要提交事务)
- 2.3 参数传递
- 2.4 模糊查询
- 3. 生命周期和生命周期
- 3.1 SqlSessionFactoryBuilder:
- 3.2 SqlSessionFactory:
- 3.3 SqlSession
- 4. 配置解析—核心配置文件
- 4.1 属性
- 4.2 设置
- 3.3 类型别名
- 4.4 环境配置
- 4.5 映射器
- 4.6 其他配置
- 5. 初识 resultMap
- 5.1 遇到的问题:数据库中的字段名 和 实体类中的字段名 不一致。
- 5.2 解法办法1:在 SQL 语句中加别名。
- 5.3 解法办法2:resultMap(结果集映射)
- 6. 分页
- 6.1 使用Mybatis实现分页
- 6.2 使用分页插件—PageHelper
- 7. 使用注解开发
- 7.1 基本使用
- 7.3 有参数的情况
- 8. 再遇 resultMap —— 高级结果映射
- 8.1 构建环境
- 8.2 复杂类型 association —— 多对一
- 8.2.1 查询结果映射
- 8.2.2 嵌套查询
- 8.3 复杂类型集合 collection —— 一对多
- 8.3.1 查询结果映射
- 8.3.2 嵌套查询
- 8.4
- 8.5 总结
- 9. 日志
- 10. 动态 SQL
- 10.1 if
- 10.2 choose
- 10.3 trim、where、set
- 10.3.1 where
- 10.3.2 set
- 10.3.3 trim
- 10.4 foreach
- 10.5 总结
- 10. 缓存
- 11. MyBatis 总结
- 点个关注,不再迷路
MyBatis
首先,什么是 MyBatis ?
官方介绍的很清楚:MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
1. 入门使用
在 Maven 项目中的使用。
先看下结构,避免一些不必要的问题。
1.1 导入相关 Maven 依赖
<!--导入依赖-->
<dependencies>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--mybatis-->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
1.2 创建并配置核心文件
在 resources 中创建一个 mybatis-config.xml. (名字可随意)
**注意:**这个配置中的数据库连接信息要换成你自己数据库的。
<?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核心配置文件 -->
<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?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="1024"/>
</dataSource>
</environment>
</environments>
<!-- Mapper 配置文件的位置 -->
<mappers>
<mapper resource="com/yuanxion/dao/UserMapper.xml"/>
</mappers>
</configuration>
1.3 编写 MyBatis 工具类
编写 MyBatis 工具类可以方便我们使用 MyBatis ,就不需要我们每次都去写这一堆代码。
public class MyBatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static{
try {
//使用Mybatis第一步:获取sqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//有了 SqlSessionFactory 之后,我们就可以从中获得 SqlSession 的实例了。
// SqlSession 完全包含了面向数据库执行 SQL 命令所需的所有方法。
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
1.4 编写实体类
这个实体类是数据库中所要操作表的对应的实体类。
类名、字段名,都要和数据库表中的一样,并提供相应的 get、set 方法。
public class User {
private int id;
private String name;
private String pwd;
public User() {
}
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + ''' +
", pwd='" + pwd + ''' +
'}';
}
}
1.5 编写实体类对应的 Mapper 接口
编写实体类对应的 Mapper 接口,并在这个借口中添加需要进行的操作,比如查询出表中所有的数据。
public interface UserMapper {
//查询所有用户信息
List<User> getUserList();
}
1.6 编写 Mapper 配置文件
原来是要实现上面的Mapper接口,现在在 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=绑定一个对应的Dao/Mapper接口 -->
<mapper namespace="com.yuanxion.dao.UserMapper">
<!-- select查询语句 -->
<select id="getUserList" resultType="com.yuanxion.pojo.User">
select * from user
</select>
</mapper>
select 标签中:
-
id : 对应的 namespace 绑定的接口中的方法名。
-
resultType:Sql 语句执行之后的返回值。
1.7 测试
测试一下数据库连接和查询:
@Test
public void test() {
//1. 得SqlSession对象
//因为前面已经写好了工具类,直接使用工具类来获取即可。
SqlSession sqlSession = MyBatisUtils.getSqlSession();
//2. 从 sqlSession 中获取所需实体类的 Mapper
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//3. 使用该 Mapper 调用我们在 Mapper 配置文件中配置的查询方法
List<User> userList = userMapper.getUserList();
//4. 遍历我们的查询结果并输出
for (User user : userList) {
System.out.println(user);
}
//5. 关闭SqlSession
sqlSession.close();
}
如果没什么问题,我们就可以链接并查询成功了。
1.8 一些可能的问题
如果发生了异常,可能是如下原因中的一种:
- 核心配置文件中的数据库连接信息没有改成自己的。
- 核心配置文件中的 Mapper 配置文件的位置 没有改成自己的。
- 方法名或返回类型写错了。
- 没有导入相应的 Maven 资源。
- 字符集问题。
- 配置文件中的写了中文注释。
虽然我写了中文注释并没有什么问题,但是发现有些人报错的原因在这里。可以删除试试。 - 更多可能的问题,根据报错信息可以去百度、谷歌等查询解决办法。
2. CRUD
2.1 Select
2.1.1 在对应 Mapper 类 UserMapper 中添加接口
//根据用户 ID 查询用户
User getUserById(int id);
2.1.2 在 Mapper 配置文件中编写 SQL 语句
<!-- 根据 ID 查询用户 -->
<select id="getUserById" parameterType="int" resultType="com.yuanxion.pojo.User">
select * from user where id = #{id}
</select>
select 标签中的:
- id : 对应的 namespace 绑定的接口中的方法名。
- resultType:Sql 语句执行之后的返回值。
- parameterType:这个SQL所对应方法传入的参数的类型。
方法传入的参数用 #{参数名} 接收,类似于一个占位符。
比如这个方法中传入的是 id,那这里就使用 #{id} 接收。
2.1.3 测试
@Test
public void testSelect() {
//第一步:获得SqlSession对象
SqlSession sqlSession = MyBatisUtils.getSqlSession();
//方式一:getMapper
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.getUserById(1);
System.out.println(user);
//关闭SqlSession
sqlSession.close();
}
2.2 Update、Delete、Insert —(增删改需要提交事务)
**注意:**增删改这3个操作需要提交事务!!(sqlSession.commit();)
2.2.1 在对应 Mapper 类 UserMapper 中添加接口
public interface UserMapper {
//根据用户 ID 查询用户
User getUserById(int id);
//新增一个用户
void addUser(User user);
//修改一个用户
void updateUser(User user);
//根据 id 删除一个用户
void deleteUser(int id);
}
2.2.2 在 Mapper 配置文件中编写 SQL 语句
<?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=绑定一个对应的Dao/Mapper接口 -->
<mapper namespace="com.yuanxion.dao.UserMapper">
<!-- 新增一个用户 -->
<insert id="addUser" parameterType="com.yuanxion.pojo.User">
insert into user (id, name, pwd) values (#{id}, #{name}, #{pwd});
</insert>
<!-- 修改一个用户 -->
<update id="updateUser" parameterType="com.yuanxion.pojo.User">
update user set name=#{name},pwd=#{pwd} where id = #{id} ;
</update>
<!-- 根据 id 删除一个用户 -->
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id};
</delete>
</mapper>
-
parameterType 传入的参数类型可以是一个对象,#{参数} 可以直接从传入的对象中获取。
比如例子中传入的是 User 对象,#{id} 就可以直接获取传入 User 对象的 id。
2.2.3 测试
我们前面两步写好之后,增、删、改 这些操作都差不多。
但是一定要注意的是:增、删、改 之后要提交事务。(sqlSession.commit();)
@Test
public void testAddUser() {
//第一步:获得SqlSession对象
SqlSession sqlSession = MyBatisUtils.getSqlSession();
//方式一:getMapper
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//创建一个 User 对象
User user = new User(33, "3333", "3333");
//添加一个User对象
userMapper.addUser(user);
//注意:增、删、改 之后,要提交事务。
sqlSession.commit();
//关闭SqlSession
sqlSession.close();
}
@Test
public void testUpdateUser() {
//第一步:获得SqlSession对象
SqlSession sqlSession = MyBatisUtils.getSqlSession();
//方式一:getMapper
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//创建一个 User 对象
User user = new User(33, "4444", "4444");
//添加一个User对象
userMapper.updateUser(user);
//注意:增、删、改 之后,要提交事务。
sqlSession.commit();
//关闭SqlSession
sqlSession.close();
}
@Test
public void testDeleteUser() {
//第一步:获得SqlSession对象
SqlSession sqlSession = MyBatisUtils.getSqlSession();
//方式一:getMapper
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//删除一个User对象
userMapper.deleteUser(33);
//注意:增、删、改 之后,要提交事务。
sqlSession.commit();
//关闭SqlSession
sqlSession.close();
}
2.3 参数传递
可以使用 Map 传参
当数据库中的表或者实体类字段过多,可以使用 Map 来传参。
//参数类型改为 Map
int addUser(Map<String,Object> map);
<!--对象中的属性,可以直接取出来。我们只需传递map的key-->
<insert id="addUser" parameterType="map">
insert into mybatis.user (id, pwd) values (#{id},#{passWord});
</insert>
@Test
public void addUser2(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
Map<String, Object> map = new HashMap<String, Object>();
map.put("id",6666);
map.put("passWord","6666");
userMapper.addUser(map);
sqlSession.commit();
sqlSession.close();
}
2.4 模糊查询
模糊查询有两种写法:
-
在 Java 程序传入参数时,加上通配符 % %
List<User> userList = mapper.getUserNameLike("%段%");
-
在 SQL 语句中拼接上通配符 % %
select * from user where name like "%"#{value}"%"
3. 生命周期和生命周期
不同作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。
3.1 SqlSessionFactoryBuilder:
**生命周期:**一旦创建了 SqlSessionFactory,就不再需要它了。
作用域:最佳作用域是方法作用域(也就是局部方法变量)。
3.2 SqlSessionFactory:
生命周期:一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
作用域:最佳作用域是应用作用域。最简单的就是使用单例模式或者静态单例模式实现。
3.3 SqlSession
生命周期: 一次请求。也就是每个请求,可以打开一个 SqlSession,返回一个响应后,就关闭这个SqlSession。
作用域:因为SqlSession 的实例是线程不安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
注意:每次使用完一个 SqlSession ,要记得关闭,不然会一直占用资源。可以把关闭操作放到 finally 块中。
一个确保 SqlSession 关闭的标准模式的实例:
try (SqlSession session = sqlSessionFactory.openSession()) {
// 你的应用逻辑代码
}
4. 配置解析—核心配置文件
核心配置文件:mybatis-config.xml (可以不取这个名字。)
- MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。
几个比较重要的配置:属性、设置、类型别名、环境配置、映射器。
4.1 属性
属性(properties)
我们可以通过properties属性来实现引用配置文件。
这些属性都是可外部配置且可动态替换的,既可以在典型的 Java 属性文件中配置,亦可通过 properties 元素的子元素来传递。
演示:
我们在资源文件夹resource中加入一个 db.properties 文件,并编写相关信息:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8
username=root
password=1024
然后在配置文件 mybatis-config.xml 中就可以直接引用:
<?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核心配置文件 -->
<configuration>
<!--引入外部配置文件-->
<properties resource="db.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>
<!-- Mapper 配置文件的位置 -->
<mappers>
<mapper resource="com/yuanxion/dao/UserMapper.xml"/>
</mappers>
</configuration>
并且,还可以通过 properties 元素的子元素来传递。
<?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核心配置文件 -->
<configuration>
<!--引入外部配置文件,并可通过子元素来传递-->
<properties resource="db.properties">
<property name="username" value="root"/>
<property name="pwd" value="1024"/>
</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>
<!-- Mapper 配置文件的位置 -->
<mappers>
<mapper resource="com/yuanxion/dao/UserMapper.xml"/>
</mappers>
</configuration>
**注意1:**如果 db.properties 和 配置文件中配置了同一个字段,会优先使用外部配置文件db.properties 的。
注意2:这核心配置文件中,标签是有顺序规定的。不过不用去记顺序,放错的顺序会有提示,根据提示修改即可。
4.2 设置
设置(settings):MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。
比如可以设置:是否开启驼峰命名自动映射、指定MyBatis所用日志的具体实现 等。
更多设置可查看:https://mybatis.org/mybatis-3/zh/configuration.html
3.3 类型别名
**类型别名 (typeAliases):**可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
比如我们在 mybatis-config.xml 中这样配置:
<!--可以给实体类起别名-->
<typeAliases>
<typeAlias type="com.yuanxion.pojo.User" alias="User"/>
</typeAliases>
这样配置之后,在 Mapper配置文件中 用这个 com.yuanxion.pojo.User 对象就可以直接使用别名 User :
<!-- 未在mybatis-config.xml中配置别名时,需要使用全限定类名 -->
<select id="getUserList" resultType="com.yuanxion.pojo.User">
select * from user
</select>
<!-- 在mybatis-config.xml中配置别名后,使用别名即可 -->
<select id="getUserList" resultType="User">
select * from user
</select>
也可以指定一个包,MyBatis 会在包名下面搜索需要的 Java Bean。
也就是说会扫描我们指定的实体类的包,然后自动给包内的实体类起别名,别名默认为 首字母小写的类名
<!--可以给指定一整个包,给实体类自动起别名,别名默认为 首字母小写的类名。-->
<typeAliases>
<package name="com.yuanxion.pojo"/>
</typeAliases>
如果是指定了一个包,并且还想自定义别名的话,可以在实体类上增加 @Alias(“xxx别名”) 注解:
public class User {
}
4.4 环境配置
环境配置(environments):MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中。
例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射 等场景。
<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>
**不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。**简单来说就是 想连接几个数据库,就需要创建几个 SqlSessionFactory 实例。
关键点:
- 默认使用的环境 ID(比如:default=“development”)。
- 每个 environment 元素定义的环境 ID(比如:id=“development”)。
- 事务管理器的配置(比如:type=“JDBC”)。
- 数据源的配置(比如:type=“POOLED”)。
Mybatis 默认的事务管理器是 JDBC ,默认使用的连接池是 : POOLED。
不过如果使用的是 Spring + MyBatis,则没有必要配置事务管理器,因为 Spring 模块会使用自带的管理器来覆盖前面的配置。
4.5 映射器
映射器 (mappers):我们配置了上述一系列 MyBatis 的行为之后,要来定义 SQL 映射语句了,而首先,我们需要告诉 MyBatis 到哪里去找到这些语句,也就是要告诉 MyBatis 到哪里去找映射文件。
简单来说就是 注册绑定我们写的的Mapper文件。
可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:///
形式的 URL),或类名和包名等方式。
方式一: 使用相对于类路径的资源引用【推荐使用】
<!-- 每一个Mapper.XML都需要在Mybatis核心配置文件中注册 -->
<mappers>
<mapper resource="com/yuanxion/dao/UserMapper.xml"/>
</mappers>
**方式二:**使用映射器接口实现类的完全限定类名
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="com.yuanxion.dao.UserMapper"/>
</mappers>
需要注意的是:
- 接口和他的Mapper配置文件必须同名。
- 接口和他的Mapper配置文件必须在同一个包下。
**方式三:**使用扫描包进行注入绑定
<!--将包内的映射器接口实现类全部注册为映射器!-->
<mappers>
<package name="com.yuanxion.dao"/>
</mappers>
同样需要注意的是:
- 接口和他的Mapper配置文件必须同名。
- 接口和他的Mapper配置文件必须在同一个包下。
4.6 其他配置
需要使用其他配置时,可去官网查看:https://mybatis.org/mybatis-3/zh/configuration.html
5. 初识 resultMap
5.1 遇到的问题:数据库中的字段名 和 实体类中的字段名 不一致。
比如 :
数据库中的字段是:id、name、pwd ;
实体类中的字段是:id、name、password 。
这样的话,当我们去查询并输出时会发现,虽然还是查询到数据,password 却为null。
因为 数据库中的字段名 和 实体类中的字段名 不一致时,无法将数据映射到不一致的字段上。
5.2 解法办法1:在 SQL 语句中加别名。
比如数据库中字段是 pwd,实体类中字段是 password,那么我们在写SQL语句时,给 pwd 起一个别名为 passw 即可。
<select id="getUserById" resultType="com.yuanxion.pojo.User">
select id,name,pwd as password from user where id = #{id}
</select>
5.3 解法办法2:resultMap(结果集映射)
编写对应数据库表和实体类的 resultMap 。
然后将 SQL语句上 resultType 改为 resultMap,并绑定对应的 resultMap 的 id。
<!-- 结果集映射 -->
<resultMap id="UserMap" type="com.yuanxion.pojo.User">
<!-- column数据库中的字段,property实体类中的属性 -->
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
<select id="getUserById" resultMap="UserMap">
select * from user where id = #{id}
</select>
注意,对于那些 数据库中的字段名 和 实体类中的字段名 一致的字段,在 resultMap 中可以省略不写:
<!-- 结果集映射 -->
<resultMap id="UserMap" type="com.yuanxion.pojo.User">
<!-- column数据库中的字段,property实体类中的属性 -->
<!-- 因为 id、name 字段一致,默认会映射,可以省略不写 -->
<result column="pwd" property="password"/>
</resultMap>
<select id="getUserById" resultMap="UserMap">
select * from user where id = #{id}
</select>
resultMap 元素是 MyBatis 中最重要最强大的元素,上面只是简单的结果映射,高级结果映射会复杂些,后面再说。
6. 分页
首先回顾一下在数据库中我们分页的语法:
SELECT * from user limit startIndex,pageSize;
简单理解就是:从第 startIndex 个开始,找 pageSize 个符合条件的数据,包含 startIndex 这个。
比如:
找出从第 0 个开始,找到 1 条符合条件的数据:
SELECT * from user limit 0,1;
找出从第 3 个开始,找到 4 条符合条件的数据:
SELECT * from user limit 3,4;
而在我们的程序中,分页的方法有很多,下面说两种:
6.1 使用Mybatis实现分页
使用方法其实和其他 Mybatis 中的 SQL 没什么区别,就是传参的时候注意一下。
用 map 传参比较方便(对因为象中的属性,可以直接取出来。我们只需传递map的key即可找到对应参数。当然也可以用其他的方式传参)。
这里说一下核心的地方:
-
mapper 接口
List<User> getUserByLimit(Map<String,Integer> map);
-
Mapper.xml 文件
<select id="getUserByLimit" parameterType="map" resultMap="UserMap"> select * from user limit #{startIndex},#{pageSize} </select>
-
使用测试:
@Test public void getUserByLimit(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); //用 map 存放分页条件 HashMap<String, Integer> map = new HashMap<String, Integer>(); map.put("startIndex",1); map.put("pageSize",2); //分页查询 List<User> userList = mapper.getUserByLimit(map); //遍历查看查询结果 for (User user : userList) { System.out.println(user); } sqlSession.close(); }
6.2 使用分页插件—PageHelper
使用插件来实现分页就很简单了,这里说的的是 PageHelper ,当然也可以使用其它分页插件。
PageHelper:https://pagehelper.github.io/
下面简单说一下使用方法:
-
在 pom.xml 中导入 PageHelper 的依赖
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.1.10</version> </dependency>
-
在 MyBatis 核心配置 MyBatis-config.xml 中配置拦截器插件
(提示:如果是 Spring 和 MyBatis 一起使用,那在二者的整合配置文件中配置即可。)<!-- 配置文件中的位置:environments 前面一个--> <plugins> <!-- com.github.pagehelper为PageHelper类所在包名,无需修改 --> <plugin interceptor="com.github.pagehelper.PageInterceptor"> <!-- 使用下面的方式配置参数,后面会有所有的参数介绍 --> <property name="helperDialect" value="mysql"/> </plugin> </plugins>
-
调用方法
就是在正常查询语句之前,设置一下分页参数即可:@Test public void testPageHelper() { SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //设置要查询第几页的数据,以及每页的大小 //比如要查询第2页的数据,每页2个数据 PageHelper.startPage(2, 2); //设置完之后,就可以查询了 List<User> userList = userMapper.getUserList(); //遍历查看查询到的数据 for (User user : userList) { System.out.println(user); } //关闭SqlSession sqlSession.close(); }
使用起来还是很简单很方便的,不过这里只是简单的示范了一下使用,更多是使用方法和使用细节,可以去查看官方文档:https://pagehelper.github.io/
大家不要一听官方文档就觉得很难,其实官方文档大部分都很通俗易懂。
7. 使用注解开发
简单的 SQL 语句,我们可以直接在相应 Mapper接口中的方法 上使用注解来实现。
7.1 基本使用
-
首先还是要在核心配置文件中还是要绑定相应接口的。
比如我们要给实现 UserMapper 接口中的方方法,那就要绑定 UserMapper :<!--绑定接口--> <mappers> <mapper class="com.yuanxion.dao.UserMapper"/> </mappers>
-
在 UserMapper 接口中的 getUserList() 上使用注解:
@Select("select * from user") List<User> getUserList();
-
就可以使用 getUserList() 方法了。
7.3 有参数的情况
有参数的时候,需要在方法参数前加上 @Param(“xxx”) 绑定字段:
@Select("select * from students where garde = #{garde} and age = #{agedeff}")
List<Student> getStudentsByGardeAndAge(@Param("garde") int garde,@Param("agedeff") int age);
注意1: 参数是基本数据类型或者String类型才要加 @Param(“xxx”) 注解;如果是引用类型的参数,不需要加。
注意2:
- @Select 注解中 #{} 中用的是 @Param() 中的字段名
- @Param() 中的字段名可以和数据字段名中不一样(不过推荐还写一样的)。
看个图可能更清楚:
(另外如果只有一个参数,可以省略@Param注解 ,不过推荐还是加上。)
8. 再遇 resultMap —— 高级结果映射
回顾:
上面我们已经简单的使用过 resultMap ——结果映射。
他的作用简单来说,就像它的名字一样,结果映射,也就是将我们从数据库中查询到的 列数据 映射到我们的 实体类中的 字段 上去。
比如
实体类的属性是:id,name,password;
数据库中的列是:id,name,pwd;
那么 resultMap 可以把我们从数据库中查询出的每条数据中的 id,name,pwd 依次分别对应到一个实体类的 id,name,password 上。
以上是简单的使用,很简单,没什么问题。
问题来了,上面都是数据库中的一个 列 对应实体类的中一个 属性,那么:
- 如果实体类中的字段是一个复杂类型,比如对象 student ,那么该怎么映射?
- 如果实体类中的字段是一个复杂类型的集合,比如 ArrayList ,那么又该怎么映射?
放心,resultMap 已经帮我们解决了这些问题。
来看一下 resultMap 中的子元素:
我们来说一下其中个常用的:
- **resutlt:**用于完成普通列的映射(上面已经使用过了)。
- **id:**用于完成主键值的映射(用法和 result 一样,唯一区别就是 id 是用于标识 主键,可提高整体性能)。
- **association:**一个复杂类型的关联,可用于嵌套结果映射。
- **collection:**多个复杂类型的集合,同样可用于嵌套结果映射。
其中 resutlt 和 id 用法简单就不再反复说了,下面结合案例重点说一下 association 和 collection。
8.1 构建环境
先建数据库表。
一个学生表,每个学生有一个老师;
一个老师表,一个老师有多个学生。
建表 SQL:
CREATE TABLE `teacher`(
`id` INT NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
CREATE TABLE `student`(
`id` INT NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT DEFAULT NULL,
PRIMARY KEY(`id`),
KEY `fktid`(`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO teacher(`id`,`name`)VALUES (1,'张三老师');
INSERT INTO teacher(`id`,`name`)VALUES (2,'李四老师');
INSERT INTO `student`(`id`,`name`,`tid`) VALUES(1,'王秀儿',1);
INSERT INTO `student`(`id`,`name`,`tid`) VALUES(2,'孙六六',1);
INSERT INTO `student`(`id`,`name`,`tid`) VALUES(3,'段诗云',1);
INSERT INTO `student`(`id`,`name`,`tid`) VALUES(4,'叶菲儿',1);
INSERT INTO `student`(`id`,`name`,`tid`) VALUES(5,'红红',2);
INSERT INTO `student`(`id`,`name`,`tid`) VALUES(6,'静静',2);
8.2 复杂类型 association —— 多对一
数据库表如上:相对于学生,是多个学生对一个老师。
实体类:
Teacher 实体类
public class Teacher {
private int id;
private String name;
//记得生成 无参、有参构造器,get、set方法,toString方法
}
Student 实体类
public class Student {
private int id;
private String name;
private Teacher teacher;
//记得生成无参、有参构造器,get、set方法,toString方法
}
(MyBatis 的环境搭建就不重复写了,这里主要是学 association 。)
需求:查询所有学生的信息以及对应老师的信息。
先看这个需求的原始 SQL 语句:
SELECT s.id sid, s.name sname, t.name tname,t.id tid
FROM student s,teacher t
WHERE s.tid = t.id
8.2.1 查询结果映射
我们可以先从数据库中查询出结果,也就是四个列的数据:sid,sname,tname,tid。
而学生实体类的字段为:id、name、teacher。
那么我们就需要将结果中的:
sid 映射到 id 上;
sname 映射到 name 上;
tname 和 tid 一起映射到 teacher 上。
具体实现就是:
<!-- association 之 查询结果映射 -->
<select id="GetStudentAndTeacher" resultMap="StudentAndTeacher">
SELECT s.id sid, s.name sname, t.name tname,t.id tid
FROM student s,teacher t
WHERE s.tid = t.id
</select>
<!-- resultMap -->
<resultMap id="StudentAndTeacher" type="com.yuanxion.pojo.Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<!--复杂类型 使用 association 来映射 -->
<association property="teacher" javaType="com.yuanxion.pojo.Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
</association>
</resultMap>
解释一下:
简单来说就是,先查询出所有字段,然后使用 resultMap 自定义映射;其中普通字段直接映射;而复杂类型,其实就是用多个字段映射成一个对象。
8.2.2 嵌套查询
思路其实就是嵌套子查询:先查出所有学生信息,再根据学生信息中的 tid 找到相应老师。
具体实现:
<!-- association 之 嵌套查询 -->
<!--1. 查询出所有的学生-->
<select id="GetStudentAndTeacher2" resultMap="StudentAndTeacher2">
SELECT * FROM student
</select>
<!-- 2.resultMap映射结果 -->
<resultMap id="StudentAndTeacher2" type="com.yuanxion.pojo.Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!--复杂类型 使用 association 来映射结果是从一个子查询中获取-->
<association property="teacher" column="tid" javaType="com.yuanxion.pojo.Teacher" select="getTeacher" />
</resultMap>
<!-- 嵌套子查询,为复杂类型赋值 -->
<select id="getTeacher" resultType="com.yuanxion.pojo.Teacher">
SELECT * FROM teacher
WHERE
id = #{tid}
</select>
解释一下:
简单来说就是嵌套子查询,子查询的整个结果作为复杂类型字段。
8.3 复杂类型集合 collection —— 一对多
collection 其实和 association 用法差不多,来看一下。
数据库表还是上面:相对于老师,是一个老师对多个学生。
实体类:
Teacher 实体类
public class Teacher {
private int id;
private String name;
//一个老师对应多个学生
private ArrayList<Student> students;
//记得生成 无参、有参构造器,get、set方法,toString方法
}
Student 实体类
public class Student {
private int id;
private String name;
private tid;
//记得生成无参、有参构造器,get、set方法,toString方法
}
(MyBatis 的环境搭建同样就不重复写了,这里主要是学 collection。)
需求:查询所有学生的信息以及对应老师的信息。
先看这个需求的原始 SQL 语句:
select s.id sid, s.name sname, t.name tname,t.id tid
from student s,teacher t
where s.tid = t.id and t.id = #{tid}
8.3.1 查询结果映射
我们可以先从数据库中查询出结果,也就是四个列的数据:tname,tid,sid,sname。
而老师实体类的字段为:id、name、ArrayList students
那么我们就需要将结果中的:
tid 映射到 id 上;
tname 映射到 name 上;
将每一对 sid 和 snname 映射到集合中的每一个对象上。
<!-- collection 之 查询结果映射 -->
<select id="getTeacherAndStudent1" resultMap="StudentAndTeacher">
select s.id sid, s.name sname, t.name tname,t.id tid
from student s,teacher t
where s.tid = t.id and t.id = #{tid}
</select>
<!-- resultMap -->
<resultMap id="StudentAndTeacher" type="com.yuanxion.pojo.Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!--复杂类型集合 使用 collection 来映射 -->
<collection property="students" ofType="com.yuanxion.pojo.Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
collection 和 association 的区别在于:
association 类型元素是 javaType = ”复杂类型所对应的实体类“
collection 类型元素是 ofType= ” 集合中复杂类型所对应的实体类“
8.3.2 嵌套查询
思路其实就是嵌套子查询:先查出所有老师;再根据老师id,去学生表中查出该老师的所有学生,放在一个集合中。
<!-- collection 之 嵌套查询 -->
<!--1. 查询出所有的老师-->
<select id="getTeacherAndStudent2" resultMap="TeacherAndStudent2">
SELECT *
FROM teacher
WHERE id = #{tid}
</select>
<!-- 2.resultMap映射结果 -->
<resultMap id="TeacherAndStudent2" type="com.yuanxion.pojo.Teacher">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!--复杂类型集合 使用 collection 来映射,结果是从一个子查询中获取-->
<collection property="students" column="id" javaType="ArrayList" ofType="Student" select="getStudent" />
</resultMap>
<!-- 嵌套子查询,为集合中的所有复杂类型赋值 -->
<select id="getStudent" resultType="com.yuanxion.pojo.Student">
SELECT * FROM student
WHERE
tid = #{tid}
</select>
简单来说就是嵌套子查询,子查询中的所有结果作为复杂类型集合。
8.4
8.5 总结
关于 association 和 collection:
- association: 用于实体类的字段是 复杂类型。比如老师对象:teacher。
- collection :用于实体类的字段是 复杂类型的集合。比如学生对象的集合:ArrayList students 。
- JavaType :用来指定实体类中普通字段的类型。比如老师实体类的类型:Teacher。
- ofType :用来指实体类中集合字段中集合元素的类型。 比如学生对象的集合中元素的类型:Student。
关于 查询结果映射 和 嵌套查询:
- 查询结果映射:
①先查询出所有字段;
②普通字段,直接映射;
③复杂类型字段,先将相应的普通字段映射成一个对象,再将这个对象映射到实体类中的复杂类型字段上。 - 嵌套查询:
①普通字段,直接查询出来,并映射。
②复杂类型字段,嵌套一个子查询,用子查询查询出数据,再映射到实体类中的复杂类型字段上。
9. 日志
日志可以帮助我们了解和记录查询的执行过程。
比如对于,MyBatis,开启日志之后,我们可以看到执行的 SQL 语句;发生错误时,便于我们排错。
MyBatis 支持的日志:
- SLF4J
- LOG4J
- LOG4J2
- JDK_LOGGING
- COMMONS_LOGGING
- STDOUT_LOGGING
- NO_LOGGING
其中常用的是 LOG4J ,STDOUT_LOGGING。
STDOUT_LOGGING 使用很简单,在核心配置文件 mybatis-config.xml 中加上下面这段配置即可:
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
LOG4J 使用使用相对复杂些,但其实也简单:
-
导入 log4j 的包
<!-- https://mvnrepository.com/artifact/log4j/log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
-
编写 log4j 的配置文件:log4j.properties 或 log4j.xml
(这里面配置很多,具体可以去百度查看)
-
在在核心配置文件 mybatis-config.xml 将日志配置成 log4j
<settings> <setting name="logImpl" value="LOG4J"/> </settings>
实际开发中,可能用 log4j 比较多。
我们这里是为了方便学习下一个知识点(动态SQL),使用 STDOUT_LOGGING 就够用了,
10. 动态 SQL
动态 SQL 是 MyBatis 的强大特性之一。
动态 SQL 可以根据方法传入的不同参数,生成不同的 SQL 。
动态 SQL 可以简化我们拼装 SQL 的操作,而无需在 Java 代码去判断和拼接。
下面就来看一下 动态 SQL 。
先搭建一下环境:
数据库:
CREATE TABLE `blog` (
`id` VARCHAR(50) NOT NULL COMMENT '博客id',
`title` VARCHAR(100) NOT NULL COMMENT '博客标题',
`author` VARCHAR(30) NOT NULL COMMENT '博客作者',
`state` VARCHAR(30) NOT NULL COMMENT '状态',
`tag` VARCHAR(30) NOT NULL COMMENT '标签'
) ENGINE=INNODB DEFAULT CHARSET=utf8
实体类:
public class Blog {
private int id;
private String title;
private String author;
private String state;
private String tag;
//构造函数、get & set 方法,toString方法。
}
10.1 if
if 可根据我们方法传入的不同条件,动态生成不同的 SQL 。
演示:
BlogMapper 中方法:
public interface BlogMapper {
ArrayList<Blog> findActiveBlogWithCondition(Map map);
}
BlogMapper.xml 中的动态 SQL :
<select id="findActiveBlogWithCondition" parameterType="map" resultType="com.yuanxion.pojo.Blog">
SELECT * FROM BLOG
WHERE state = '上架'
<if test="title != null">
AND title like #{title}
</if>
<if test="tag != null">
AND tag like #{tag}
</if>
</select>
我们的参数放在一个 map 中,根据我们写的动态 SQL 语句:
-
当我们的 map 中没有参数时,SQL 语句是
SELECT * FROM BLOG WHERE state = '上架' ;
-
我们的 map 中有 <“tag”, “算法”> 一个键值对时,SQL 语句是
SELECT * FROM BLOG WHERE state = '上架' AND tag like '算法';
-
我们的 map 中有 <“tag”, “算法”>,<“title”, “Java”> 时,SQL 语句是
SELECT * FROM BLOG WHERE state = '上架' AND title like 'Java' AND tag like '算法';
10.2 choose
上面的 if 会使用所有传入的满足条件的条件,但有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。
针对这种情况,MyBatis 提供了 choose 元素,它有点**像when 有一个条件满足时,会拼接这个满足条件 when 中的语句,不会再拼接 otherwise 中的语句。
演示:
BlogMapper 中方法:
public interface BlogMapper {
ArrayList<Blog> findActiveBlogWithOneCondition(Map map);
}
BlogMapper.xml 中的动态 SQL :
<select id="findActiveBlogWithOneCondition" parameterType="map" resultType="com.yuanxion.pojo.Blog">
SELECT * FROM BLOG
WHERE state = '上架'
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null">
AND author like #{author}
</when>
<otherwise>
AND tag like 'Java'
</otherwise>
</choose>
</select>
我们的参数放在一个 map 中,根据我们写的动态 SQL 语句:
-
当我们的 map 中没有参数时,SQL 语句是
SELECT * FROM BLOG WHERE state = '上架' AND tag like 'Java'
when 里面条件没满足,就会默认拼接 otherwise 中的语句。
-
我们的 map 中有 <“author”, “猿兄”> 一个键值对时,SQL 语句是
SELECT * FROM BLOG WHERE state = '上架' AND author like '猿兄';
when 有一个条件满足时,会拼接这个满足条件 when 中的语句,不会再拼接 otherwise 中的语句。
-
我们的 map 中有 <“author”, “猿兄”>,<“title”, “Mybatis解析”> 时,SQL 语句是
SELECT * FROM BLOG WHERE state = '上架' AND title like 'Mybatis解析';
when 有多个条件满足时,会拼接满足条件 when 中,位置最上面的语句,不会再拼接其他 when 中的语句 以及 otherwise 中的语句。
10.3 trim、where、set
10.3.1 where
来看个问题,我们上面的动态语句中,where 后面是有个默认条件 state = ‘上架’ 的:
<select id="findActiveBlogWithCondition" parameterType="map" resultType="com.yuanxion.pojo.Blog">
SELECT * FROM BLOG
WHERE state = '上架'
<if test="title != null">
AND title like #{title}
</if>
<if test="tag != null">
AND tag like #{tag}
</if>
</select>
如果这个 state = ‘上架’ 也是可选条件,那么就变成了下面这种写法:
<select id="findBlogWithCondition" parameterType="map" resultType="com.yuanxion.pojo.Blog">
SELECT * FROM BLOG
WHERE
<if test="state != null">
state like #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="tag != null">
AND tag like #{tag}
</if>
</select>
这样的写法,如果每次查找条件中都有 state 条件那就没问题;
可是如果条件中没有第一个 state 条件,动态生成的 SQL 就会出问题。
比如,只给了 tag = ‘Java’ 条件,那么动态生成的 SQL就变成了:
SELECT * FROM BLOG
WHERE
AND tag like 'Java'
可以看到,WHERE 后面多了一个 AND 。
这是不是就不太智能了?
放心,其实将 WHERE 改为 元素即可:
<select id="findBlogWithCondition" parameterType="map" resultType="com.yuanxion.pojo.Blog">
SELECT * FROM BLOG
<where>
<if test="state != null">
state like #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="tag != null">
AND tag like #{tag}
</if>
</where>
</select>
元素,如果第一个条件不存在,他拼接后面的 SQL 时,会自动删除掉 WHERE 子句开头多余的 AND 或 OR。
10.3.2 set
set 元素和 where 元素功能差不多。
where 元素是删除自动删除 WHERE 子句开头多余的 AND 或 OR;
set 元素是自动删除 SET 子句结尾多余的 “,” 。
<update id="updateBlog" parameterType="map">
update blog
<set>
<if test="state != null">
state like #{state},
</if>
<if test="title != null">
title = #{title},
</if>
<if test="author != null">
author = #{author}
</if>
</set>
where id = #{id}
</update>
10.3.3 trim
当上面的 where 元素和 set 元素不能满足你的动态SQL 时,可以使用自定义的 trim 元素。
trim 属性:
属性 | 描述 |
---|---|
prefix | 给sql语句拼接的前缀 |
suffix | 给sql语句拼接的后缀 |
prefixOverrides | 去除sql语句前面的关键字或者字符,该关键字或者字符由prefixOverrides属性指定,假设该属性指定为"AND",当sql语句的开头为"AND",trim标签将会去除该"AND" |
suffixOverrides | 去除sql语句后面的关键字或者字符,该关键字或者字符由suffixOverrides属性指定 |
比如我们可以用 trim 自定义成一个和 set 一样的功能的元素:
<update id="updateBlog" parameterType="map">
update blog
<trim prefix="SET" suffixOverrides=",">
<if test="state != null">
state like #{state},
</if>
<if test="title != null">
title = #{title},
</if>
<if test="author != null">
author = #{author}
</if>
</trim>
where id = #{id}
</update>
10.4 foreach
动态 SQL 的可以利用 foreach 元素对集合进行遍历。
比如,基于上面的环境,我们想实现是一个方法,查找指定id的一些博客:
Mapper:
public interface BlogMapper {
ArrayList<Blog> findBlogByIds(List<Integer> list);
}
Mapper.xml:
<select id="findBlogByIds" parameterType="list" resultType="com.yuanxion.pojo.Blog">
SELECT *
FROM BLOG
WHERE ID in
<foreach collection="list" item="id" index="index"
open="(" separator="," close=")">
#{id}
</foreach>
</select>
foreach 元素允许指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。
它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素会智能的添加,不会错误地添加多余的分隔符。
提示 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
那我们上面写的 feach 的动态SQL 来说:
-
如果 list 中只有一个值 1,那么动态生成的 SQL 就是:
SELECT * FROM BLOG WHERE ID in (1)
-
如果 list 中只有3个值 1、3、4,那么动态生成的 SQL 就是:
SELECT * FROM BLOG WHERE ID in (1,3,4)
-
… …
10.5 总结
简单来说,动态 SQL 其实就是可以根据不同的条件,动态不同的SQL ;让我们可以简化拼装 SQL 的操作,而无需在 Java 代码中去判断和拼接。
10. 缓存
MyBatis 内置了一个事务性缓存机制。
(这个了解即可,真要使用缓存的话,还是要使用 Redis 或 Memcached 实现缓存。)
MyBatis 的缓存有两个级别:一级缓存 和 二级缓存。
**一级缓存(默认):**本地的会话缓存;可以理解为 SqlSession级别的缓存,也就是这个级别的缓存只在一个 SqlSession 中有效,然后这个 SqlSession 关闭了,这个缓存就没了。
**二级缓存:**全局缓存;可以理解为 SqlSessionFactory 级别的缓存,也就是这个级别的缓存,在所有这个 SqlSessionFactory 生成的 SqlSession 中共享。当一个 SqlSession 被关闭之前,会将其缓存保存。
默认是开启一级缓存,如果想开启二级缓存,只需要在你的 Mapper.xml 映射文件中添加一行:
<cache/>
加上之后的默认效果:
- 映射语句文件中的所有 select 语句的结果将会被缓存。
- 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
- 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
- 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
- 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
- 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
提示 :缓存只作用于 cache 标签所在的映射文件中的语句。如果你混合使用 Java API 和 XML 映射文件,在共用接口中的语句将不会被默认缓存。你需要使用 @CacheNamespaceRef 注解指定缓存作用域。
然后上述的效果,可以通过 cache 元素的属性来修改,比如:
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
这个配置的意思是:创建了一个清除策略为 FIFO 的缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
清除策略是当缓存空间不足时,删除已有的缓存,来清理空间的策略,可用的清除策略有:
LRU
– 最近最少使用:移除最长时间不被使用的对象。FIFO
– 先进先出:按对象进入缓存的顺序来移除它们。SOFT
– 软引用:基于垃圾回收器状态和软引用规则移除对象。WEAK
– 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
**注意:**因为增删改操作,可能会改变原来的数据,所以增删改操作会刷新缓存!
然后缓存的方式除掉上面的方式,还可以自定义缓存方式,了解就好;当然,有兴趣的可以去研究研究。(我就不去研究自定义缓存了,我选择用 Redis /手动狗头。)
11. MyBatis 总结
首先 MySQL 的基本使用很简单。
基本使用流程:
-
在pom.xml 中导入相关依赖
-
创建核心配置文件:mybatis-config.xml
2.1 在配置文件中配置数据库连接信息;可以引入外部资源文件中的数据库连接信息。
-
创建实体类
-
创建实体类对应的 Mapper 接口,在接口中定义相关方法。
-
创建 Mapper 接口对于的 Mapper.xml 映射文件
5.1 在核心配置文件 mybatis-config.xml 中绑定,或者说注册这个 Mapper.xml 映射文件。5.2 在映射文件中用 namespace 声明所有绑定的对应的 Mapper 接口。
5.3 实现 Mapper 接口中定义的方法。 -
开始使用
6.1 读取核心配置文件 Mapper.xml ,生成相应的 SqlSessionFactory;
6.2 使用这个SqlSessionFactory 生成相应的 SqlSession 。
6.2 使用这个 SqlSession 去调用接口中的定义的方法。
(其中 6.1、6.2 可以封装成一个 Utils,方便多次使用。)
并且知道了,MyBatis 不止可以通过映射文件来开发,还可以通过注解来开发;
不过复杂的 SQL 语句用注解开发不方便,还得同 Mapper.xml 映射文件来开发。
然后又知道了 resultMap——结果集映射。
其中
- 简单的字段,可以用 resutlt 直接映射。
- 复杂类型的字段,要用 association 来映射。
- 复杂类型集合的字段,要用 collection 来映射。
这里面,顺便还知道了复杂查询的两种解决方法:
- 查询结果映射:先查询出所有结果;简单字段直接映射;复杂字段,先映射成对应的对象再整个映射。
- 嵌套查询:其实就是分步查询,或者说嵌套子查询。
然后还知道了怎么开启日志,来查看具体的执行信息。
再然后,知道了动态SQL,简单来说也就是根据传入的参数的不同,动态生成不同的 SQL 。
- if
- choose
- foreach
最后的最后还了解一下MyBatis的缓存:
- 一级缓存 :本地会话缓存。
- 二级缓存:全局缓存。
至此,MyBatis 大部分内容应该都说到了。
如果有没有提到的内容,而项目又需要的话,可以去官方文档查阅:中文官方文档
最后的最后还要再说一句,真正想要精通 MyBatis ,还得要多去使用多去思考,在不断使用中和思考中,才能学会更多!
点个关注,不再迷路
不要明知会后悔却还不去努力!
这里是猿兄,为你分享程序员的世界。
非常感谢各位**优秀的程序员**们能看到这里,如果觉得文章还不错的话,求点赞???? 求关注???? 求分享????,对我来说真的 非常有用!!!
持续更新文章,欢迎微信搜索关注: 猿兄 第一时间获取最新文章。
关注后回复【电子书】,有我为大家准备的各类技术书籍。
最后
以上就是香蕉咖啡豆为你收集整理的万字 MyBatis 带你从入门到精通!!!MyBatis的全部内容,希望文章能够帮你解决万字 MyBatis 带你从入门到精通!!!MyBatis所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复