框架系列课程-Mybatis
mybatis系列教程
文章目录
- 1. Mybatis入门
- 2. Mybatis参数传递
- 3. Mybatis 单表CURD操作
- 4. Mybatis 关联关系
- 5 Mybatis 缓存
- 6 Mybatis 分页插件
1. Mybatis入门
1.0 JDBC代码
//利用jdbc,完成新增的功能
private static void method2() throws Exception{
//1,注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2,获取数据库的连接
//数据传输协议 数据库的ip 端口号 数据库名
String url = "jdbc:mysql://localhost:3306/cgb2107";
Connection c = DriverManager.getConnection(url,"root","root");
//3,获取传输器
Statement s = c.createStatement();
//4,利用传输器执行 增删改的SQL
//executeUpdate()用来执行增删改的SQL,只返回影响行数
int rows = s.executeUpdate(
"INSERT INTO emp(ename,job) VALUES('rose','副总')");
//5,释放资源
//r.close();//结果集
s.close();//传输器
c.close();//连接
}
从中可以看出JDBC的开发效率很低.
1.1 Mybatis介绍
官网地址: https://mybatis.org/mybatis-3/zh/index.html
- MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。
- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
- MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
- MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。
- 2013年11月迁移到Github。
1.2 Mybatis源码
1.3 Mybatis特点
- MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架
- MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集
- MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Ordinary Java Object,普通的Java对象)映射成数据库中的记录
- Mybatis 是一个 半自动的ORM(Object Relation Mapping)框架
1.4 Mybatis入门案例
1.4.1 导入jar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.atguigu</groupId>
<artifactId>mybatis_demo1</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--导入MySQL的驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<!--导入MyBatis的jar包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--log4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--导入lombokjar包-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
1.4.2 编辑User POJO对象
@Data
@Accessors(chain = true)
public class User implements Serializable {
private Integer id;
private String name;
private Integer age;
private String sex;
}
1.4.3 编辑mybaits-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>
<!--设置连接数据库的环境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/atweb?serverTimezone=UTC&rewriteBatchedStatements=true&characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--引入映射文件-->
<mappers>
<mapper resource="mappers/UserMapper.xml"/>
</mappers>
</configuration>
1.4.4 编辑UserMapper接口
public interface UserMapper {
List<User> getAllUser();
}
1.4.5 编辑接口实现类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">
<mapper namespace="com.atguigu.mybatis.mapper.UserMapper">
<select id="getAllUser" resultType="com.atguigu.mybatis.pojo.User">
select * from demo_user
</select>
</mapper>
1.4.6 mybatis关联映射文件
1.4.7 编辑SqlSessionFactory
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。
/*创建SqlSessionFactory*/
String resource = "mybatis/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
1.4.8 从 SqlSessionFactory 中获取 SqlSession
既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。
@Test
public void testDemo1() throws IOException {
/*创建SqlSessionFactory*/
String resource = "mybatis/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
/*从SqlSessionFactory中获取sqlSession*/
SqlSession sqlSession = sqlSessionFactory.openSession();
}
1.4.9 执行业务调用
@Test
public void testDemo1() throws IOException {
/*创建SqlSessionFactory*/
String resource = "mybatis/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
/*从SqlSessionFactory中获取sqlSession*/
SqlSession sqlSession = sqlSessionFactory.openSession();
/*获取mapper接口,执行接口方法*/
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = userMapper.findAll();
System.out.println(userList);
}
1.4.10 mybatis入门案例总结
Mysql入门实现步骤:
1.编辑mybatis-config.xml核心配置文件
1.1执行数据源配置
2.编辑POJO实体对象.要求与数据库表中的字段一一对应
3.编辑Mapper接口. 添加接口方法
4.编辑接口的实现类(配置文件方式) 要求namespace id resultType
5.mybatis加载指定的mapper映射文件
6.创建SqlSessionFactory工厂对象
7.获取SqlSession,开启数据库链接
8.获取接口对象(代理对象)
9.调用接口方法,获取返回值结果
10.关闭sqlSession链接.
1.5 Mybatis常见错误
1.5.1 BindingException异常说明
报错说明1:
org.apache.ibatis.binding.BindingException: Type interface com.jt.mapper.UserMapper is not known to the MapperRegistry.
解决方案1:
检查namespace命名是否与接口一致
报错说明2:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.jt.mapper.UserMapper.findAll
解决方案2:
检查xml映射文件中的ID是否与接口方法一致.
报错说明3:
The error may exist in mybatis/mappers/UserMapper2.xml
解决方案3:
检查mybatis核心文件加载mapper映射文件的路径是否正确.
1.6 SqlSession 简化操作
package com.jt;
import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
class MybatisApplicationTests {
private SqlSessionFactory sqlSessionFactory;
@BeforeEach
public void init() throws IOException {
/*创建SqlSessionFactory*/
String resource = "mybatis/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testDemo2() {
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = userMapper.findAll();
System.out.println(userList);
sqlSession.close();
}
}
1.7 SqlSession扩展方法(过时不建议使用)
说明: 可以通过namespace名称.ID的方式直接调用sql
//知识扩展,利用namespace获取数据
@Test
public void testDemo3() {
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> userList = sqlSession.selectList("com.jt.mapper.UserMapper.findAll");
System.out.println(userList);
sqlSession.close();
}
1.8 日志功能
1.8.1 引入日志文件目的
-
设定级别,统一管理
日志框架会按照事件的严重程度来划分级别,例如:- 错误(Error):表示程序运行出错,比如抛异常等情况。
- 警告(Warning):表示程序运行过程中有潜在风险,但此时并没有报错。
- 信息(Info):表示程序运行过程中完成了一个关键动作,需要以程序运行信息的形式告知开发者。
- 调试(Debug):表示程序运行过程中更加细致的信息,协助程序员调试程序。
-
灵活指定输出位置
使用日志框架不一定是打印到控制台,也可以保存到文件中或者保存到数据库。这就看具体的项目维护需求。 -
自定义日志格式
打印日志数据可以使用日志框架的默认格式,也可以根据需要定制。 -
基于日志分析问题
将来我们开发的应用系统中,不仅包含Java代码,还有很多中间件服务器。任何子系统出现故障我们都是通过日志来定位问题、分析故障原因。甚至更复杂的系统还会专门开发日志子系统,在主系统出现问题时抓取日志数据供维护人员参考。
1.8.2 常见日志
1.8.3 导入jar包
<!-- 日志 , 会自动传递slf4j门面-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
1.8.4 日志入门案例
public class TestLog {
private Logger logger = LoggerFactory.getLogger(TestLog.class);
@Test
public void testlog(){
logger.debug("hello debug");
logger.info("hello info");
logger.warn("hello warning");
logger.error("hello error");
}
}
1.8.5 自定义日志
Logback要求配置文件名称必须是logback.xml,存放路径在main/resources目录下。
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
<!-- 指定日志输出的位置,ConsoleAppender表示输出到控制台 -->
<appender name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- 日志输出的格式 -->
<!-- 按照顺序分别是:时间、日志级别、线程名称、打印日志的类、日志主体内容、换行 -->
<pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 设置全局日志级别。日志级别按顺序分别是:TRACE、DEBUG、INFO、WARN、ERROR -->
<!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
<root level="DEBUG">
<!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender -->
<appender-ref ref="STDOUT" />
</root>
<!-- 根据特殊需求指定局部日志级别,可也是包名或全类名。 -->
<logger name="com.atguigu.mybatis" level="DEBUG" />
</configuration>
1.9 动态配置数据源
1.9.1 编辑properties文件
说明: 在src/main/resources/jdbc.properties 创建配置文件
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/atweb?serverTimezone=UTC&rewriteBatchedStatements=true&characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
1.9.2 动态获取数据源信息
<?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>
<!--
(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)".
-->
<properties resource="jdbc.properties"></properties>
<!--设置连接数据库的环境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!-- <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/atweb?serverTimezone=UTC&rewriteBatchedStatements=true&characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>-->
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!--引入映射文件-->
<mappers>
<mapper resource="mappers/UserMapper.xml"/>
</mappers>
</configuration>
1.10 Mybatis属性定义
1.10.1 别名定义
可以通过别名配置简化返回值操作
1.配置文件别名 注意位置 在environments环境之上创建
<!--定义别名-->
<typeAliases>
<typeAlias type="com.jt.pojo.User" alias="User"></typeAlias>
</typeAliases>
1.10.2 别名包定义
<!--定义别名-->
<typeAliases>
<!--定义别名-->
<!--<typeAlias type="com.jt.pojo.User" alias="User"></typeAlias>-->
<!--定义别名包-->
<package name="com.jt.pojo"/>
</typeAliases>
1.10.3 注解别名
3. 代码测试
1.10.4 Sql标签
可以通过Sql标签简化程序调用.
<sql id="select_demo_user">
select * from demo_user
</sql>
<select id="selectUserListByLike" resultType="user">
<include refid="select_demo_user"/> where name like #{name}
</select>
2. Mybatis参数传递
2.1 #号和$符介绍
- #号作用:
- 其本质为占位符赋值. 有预编译效果, 会自动添加一对引号
<select id="findUserByName" resultType="com.atguigu.mybatis.pojo.User">
select * from demo_user where name=#{name}
</select>
- $符作用:
- 其本质为字符串拼接, 所以需要手动拼接引号, 没有预编译效果.
- 一般用到以字段名称为参数的案例中
$符改进:
<select id="findUserByName" resultType="com.atguigu.mybatis.pojo.User">
select * from demo_user where name='${name}'
</select>
- 总结: 能用#号 不要用$
2.2 单值传递
业务说明:
1. 使用#号和$
符时,如果只有一个参数时,使用任意名称都可以获取参数
2. 但是使用$
{} 时 不能以数字为参数
3. 使用$
符时应该注意字符串参数的引号, 如果是数值类型可以直接使用$符
2.3 多个参数传递
业务说明: 当数据有多个参数时 默认条件下使用 param1,param2 或者arg0,arg1的方式获取数据
Mybatis多值传递说明:
Mybatis中会将多个参数自动封装为map集合,如果不指定key 则默认采用param1,param2的方式以 key=value的方式实现数据存储. 之后通过#{key}的方式实现数据获取
<!--
//arg1, arg0, param1, param2
-->
<select id="findUserByNameAndAge" resultType="User">
<!--select * from demo_user where name=#{arg0} and age=#{arg1}-->
select * from demo_user where name=#{param1} and age=#{param2}
</select>
2.3 Map集合参数传递
业务说明: 如果需要自定义参数key,则可以使用Map集合的方式实现数据封装.
1.测试方法调用
2. Mapper接口定义
User finduserByMap(Map<String, Object> map);
- 映射文件实现
<!--
User finduserByMap(Map<String, Object> map);
-->
<select id="finduserByMap" resultType="User">
select * from demo_user where name=#{name} and age=#{age}
</select>
2.4 实体对象封装数据
说明: 当有多个参数时,可以采用实体对象的方式传递数据,但是必须要求对象有get/set方法
- 编辑测试API
//User对象传递数据
@Test
public void test05() throws IOException {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = new User();
user.setId(null).setAge(742).setName("辟尘大王").setSex("男");
List<User> userList = mapper.selectUser(user);
userList.forEach(System.out::println);
}
- 编辑测试接口
List<User> selectUser(User user);
- 编辑测试映射文件
<select id="selectUser" resultType="User">
select * from demo_user where name=#{name} and age=#{age} and sex=#{sex}
</select>
2.5 注解参数赋值
说明: mybatis中提供了注解@param, 可以通过该注解将数据封装为Map集合. 之后根据key进行调用
参数说明: [name, param1, age, param2]
- 编辑测试类
//@Param注解 实现参数传递
@Test
public void test06() throws IOException {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
String name = "辟尘大王";
int age = 742;
List<User> userList = mapper.selectParam(name,age);
userList.forEach(System.out::println);
}
- 编辑业务接口
List<User> selectParam(@Param("name") String name, @Param("age") int age);
- 编辑映射文件
<!--
List<User> selectParam(@Param("name") String name, @Param("age") int age);
-->
<select id="selectParam" resultType="User">
select * from demo_user where name=#{a} and age=#{age}
</select>
2.6 package标签说明
如果有多个xml映射文件,则使用mappers中的package标签实现功能,需要注意 包路径信息应该与mapper接口路径一致.
<!--引入映射文件-->
<mappers>
<!--需要指定mapper接口的包路径.-->
<!--<mapper resource="mappers/UserMapper.xml"/>-->
<!--<package name="com.atguigu.mybatis.mapper"/>-->
<package name="com.atguigu.mybatis.mapper"/>
</mappers>
3. Mybatis 单表CURD操作
3.1 根据ID查询数据
3.1.1 需求说明
查询id=1的用户数据
3.1.2 编辑接口方法
3.1.3 编辑UserMapper.xml 映射文件
<!--根据ID查询用户数据-->
<select id="findUserById" parameterType="Integer" resultType="com.jt.pojo.User">
select * from demo_user where id = #{id}
</select>
3.1.4 编辑单元测试方法
@Test
public void testUserById(){
int id = 1;
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.findUserById(id);
System.out.println(user);
sqlSession.close();
}
3.2 测试新增/修改/删除
3.2.1 编辑业务接口
public interface UserMapper {
//查询所有的User列表信息
List<User> findAll();
User findUserById(Integer id);
//实现数据新增
int saveUser(User user);
int updateUser(User user);
int deleteUserById(Integer id);
}
3.2.2 编辑Mapper映射文件
<!--实现数据新增 新增成功之后自动返回影响的行数
数据取值时 使用#{属性名} 获取数据
-->
<insert id="saveUser" parameterType="com.jt.pojo.User">
insert into demo_user(id,name,age,sex) value (null,#{name},#{age},#{sex})
</insert>
<update id="updateUser" parameterType="com.jt.pojo.User">
update demo_user set name = #{name}, age = #{age}, sex = #{sex} where id = #{id}
</update>
<delete id="deleteUserById" parameterType="Integer">
delete from demo_user where id = #{id}
</delete>
3.2.3 编辑测试方法
@Test
public void testSaveUser(){
User user = new User(null,"中秋节",2021,"女");
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int rows = userMapper.saveUser(user);
if(rows > 0 ){
System.out.println("事物提交");
sqlSession.commit();
}
System.out.println(rows);
sqlSession.close();
}
@Test
public void testUpdateUser(){
User user = new User(234,"中秋节BBBB",2021,"女");
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int rows = userMapper.updateUser(user);
if(rows > 0 ){
System.out.println("事物提交");
sqlSession.commit();
}
System.out.println(rows);
sqlSession.close();
}
@Test
public void testDeleteUserById(){
int id = 237;
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int rows = userMapper.deleteUserById(id);
if(rows > 0 ){
System.out.println("事物提交");
sqlSession.commit();
}
System.out.println(rows);
sqlSession.close();
}
3.3 利用Map查询数据
3.3.1 业务需求
需求: 查询age >= 18岁 age<= 100岁的用户
3.3.2 编辑业务接口
3.3.3 编辑映射文件
<!--特殊转义字符
> >
< <
& &
万能转义标签 <![CDATA[ 需要转义的内容 ]]>
-->
<select id="findUserListByAge" parameterType="map" resultType="com.jt.pojo.User">
select * from demo_user where age >= #{minAge} and age <= #{maxAge}
</select>
3.3.4 编辑测试代码
/**
* 查询age>=18 age<=100岁的用户
*/
@Test
public void testSelectUserListByAge(){
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
Map map = new HashMap();
map.put("minAge",18);
map.put("maxAge",100);
List<User> userList = userMapper.findUserListByAge(map);
System.out.println(userList);
}
3.4 查询结果 返回值为Map
说明: 有时可能找不到适合封装数据的对象,则可以使用Map集合实现结果集接收, 但是需要注意 返回值结果为一条时 使用map集合封装, 如果记录有多条 使用List
查询条件2: 查询所有数据,返回值Map 接收数据List<Map<k,v>>
查询条件3: 查询所有数据,返回值Map 接收数据Map Map<key: Map<>>
3.4.1 编辑测试类
@Test
public void test01() throws IOException {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String,Object> map = mapper.findMap();
map.forEach((k,v) -> {
System.out.println(k+":"+v);
});
}
@Test
public void test02() throws IOException {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<Map<String,Object>> list = mapper.findMapList();
list.forEach(user -> {
System.out.println(user);
});
}
@Test
public void test03() throws IOException {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map map = mapper.findUserToMap();
map.forEach((k,v) -> {
System.out.println(k+":"+v);
});
}
3.4.2 编辑接口
public interface UserMapper {
//将user结果使用map类型返回
Map<String, Object> findMap();
List<Map<String, Object>> findMapList();
//通过关键字 实现数据查询
@MapKey("id")
Map findUserToMap();
}
3.4.3 编辑映射文件
<?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.atguigu.mybatis.mapper.UserMapper">
<select id="findMap" resultType="map">
select * from demo_user where id=2
</select>
<select id="findMap" resultType="map">
select * from demo_user where id=2
</select>
<select id="findMapList" resultType="map">
select * from demo_user
</select>
<select id="findUserToMap" resultType="map">
select * from demo_user
</select>
</mapper>
3.5 主键自动回显
当开启主键自增时, 则通过对象的方式获取主键自增的属性
3.5.1 编辑测试类
@Test
public void test04() throws IOException {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = new User();
user.setSex("女");
user.setName("Mybatis测试案例");
user.setAge(100);
int id = mapper.insertUser(user);
sqlSession.commit();
System.out.println("动态获取返回值:"+id);
System.out.println("动态获取ID主键信息:"+user.getId());
}
3.5.2 编辑测试接口
int insertUser(User user);
3.5.3 编辑xml映射文件
<!--
useGeneratedKeys="true" 开启主键自增操作
keyProperty="id" 将主键为属性赋值.
-->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
insert into demo_user values (null,#{name},#{age},#{sex})
</insert>
3.6 模糊查询用法
3.6.1 业务需求
查询name属性中包含"君"的数据
3.6.2 业务接口
List<User> selectUserListByLike(Map map);
3.6.3 编辑xml映射文件
<!--<select id="selectUserListByLike" resultType="com.jt.pojo.User">
select * from demo_user where name like "%"#{name}"%"
</select>-->
<select id="selectUserListByLike" resultType="com.jt.pojo.User">
select * from demo_user where name like #{name}
</select>
3.6.4 编辑测试方法
/**
* 查询 name中包含'君'字的数据
*/
@Test
public void testSelectUserListByLike(){
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
Map map = new HashMap();
//map.put("name","君");
map.put("name","%君%");
List<User> userList = userMapper.selectUserListByLike(map);
System.out.println(userList);
}
3.7 Mybatis 集合参数写法 list/array/map
3.7.1 业务说明
当mybaits需要批量操作时,需要使用list/array/或者map进行数据封装
3.7.1 编辑接口
void deleteIds(List list);
3.7.2 编辑xml映射文件
<delete id="deleteIds" parameterType="list">
delete from demo_user where id in
<foreach collection="list" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</delete>
如果是批量更新/新增等操作 则需要添加特定属性: 关键词: allowMultiQueries=true
mysql.url=jdbc:mysql://localhost:3306/atweb?serverTimezone=UTC&allowMultiQueries=true&rewriteBatchedStatements=true&characterEncoding=utf-8
3.8 动态Sql-where条件
3.8.1 编辑测试方法
/*动态Sql*/
@Test
public void testSelect(){
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = new User();
user.setName("王昭君");
List<User> userList = userMapper.selectByUser(user);
System.out.println(userList);
}
3.8.2 映射方法
<select id="selectByUser" parameterType="user" resultType="user">
select * from demo_user
<where>
<if test="name !=null"> name = #{name}</if>
<if test="sex !=null"> and sex = #{sex}</if>
<if test="age !=null"> and age = #{age}</if>
<if test="sex !=null"> and sex = #{sex}</if>
</where>
</select>
3.9 动态Sql-set条件
3.9.1 编辑测试方法
/*动态Sql 更像操作
* 修改ID=236的用户数据 名称改为张三,age=18,sex=女
* */
@Test
public void testUpdate(){
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = new User(236,"张三",18,"女");
int rows = userMapper.updateUserSet(user);
if(rows > 0){
sqlSession.commit();
}
sqlSession.close();
}
3.9.2 映射方法
<update id="updateUserSet" parameterType="user">
update demo_user
<set>
<if test="name !=null">name = #{name},</if>
<if test="age != null"> age = #{age},</if>
<if test=" sex != null"> sex = #{sex}</if>
</set>
where id = #{id}
</update>
3.10 trim关键字
说明: 如果需要去掉额外的关键字 则建议使用trim关键字
语法说明:
- prefix=“where” 添加前缀
- prefixOverrides=“and|or” 去掉前边的关键字 如果有多个使用|线隔开
- suffix=“;” 为后缀添加数据
- suffixOverrides=“and|or” 去掉后边的关键字 如果有多个使用|线隔开
3.10.1 编辑测试类
@Test
public void testTrim(){
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = new User(149,null, null,"女");
List<User> list = mapper.findTrim(user);
System.out.println(list);
}
3.10.2 编辑映射文件
<select id="findTrim" resultType="User">
select * from demo_user
<trim prefix="where" prefixOverrides="and|or" suffix=";" suffixOverrides="and|or">
<if test="id !=null"> and id=#{id} </if>
<if test="name !=null">and name=#{name} </if>
<if test="sex !=null">and sex = #{sex} </if>
<if test="age !=null">and age = #{age} </if>
</trim>
</select>
3.11 动态Sql-choose、when、otherwise
3.11.1 业务需求说明
说明: 如果不想使用所有的条件可以使用choose 类似于java中的switch 语法
如果name有值,则按照name查询,否则按照sex查询数据.
3.11.2 编辑测试类
@Test
public void selectChoose(){
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = new User(null,null,null,"男");
List<User> list = userMapper.selectChoose(user);
System.out.println(list);
}
3.11.3 编辑xml映射文件
<!--其中的用法类似于switch-->
<select id="selectChoose" resultType="User">
select * from demo_user
<where>
<choose>
<when test="name !=null">
name = #{name}
</when>
<otherwise>
sex = #{sex}
</otherwise>
</choose>
</where>
</select>
3.12 resultMap介绍
3.12.1 需求说明
当表中的字段与POJO中的属性不能完全匹配时, 则需要使用resultMap映射.
3.12.2 表设计说明
3.12.3 编辑POJO对象
3.12.4 编辑测试方法
@Test
public void selectDog(){
SqlSession sqlSession = sqlSessionFactory.openSession();
DogMapper dogMapper = sqlSession.getMapper(DogMapper.class);
List<Dog> dogList = dogMapper.findAll();
System.out.println(dogList);
}
3.12.5 编辑xml映射文件
<!--
autoMapping: 如果字段与名称相同,是否自动映射, 默认值为true 旧版本为false
id: resultMap的主键标识 可以复用
-->
<resultMap id="dogRM" type="Dog" autoMapping="false">
<id column="dog_id" property="dogId"></id>
<result column="dog_name" property="dogName"/>
</resultMap>
<select id="findAll" resultMap="dogRM">
select * from demo_dog
</select>
3.13 开启驼峰规则映射
可以通过settings设置 是否开启驼峰规则映射
官网: https://mybatis.org/mybatis-3/zh/configuration.html#settings
<settings>
<!--是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
3.14 Mybatis注解开发(扩展)
3.14.1 常用注解
使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL 语句更加混乱不堪。 因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句。
3.14.2 常用注解
@Select(“select * from demo_user”)
@Update()
@Delete()
@Insert()
List findAll()
3.14.3 Mybatis绑定Mapper接口
3.14.4 单元测试
@Test
public void selectAnno(){
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper2 userMapper2 = sqlSession.getMapper(UserMapper2.class);
System.out.println(userMapper2.findAll());
}
注意事项: 多个参数调用时注意数据封装
@Select("select * from demo_user where name = #{name} and sex = #{sex}")
List<User> findUserByNS(@Param("name") String name,@Param("sex") String sex);
4. Mybatis 关联关系
4.1 常见关联关系
1.一对一 一个员工对应一个部门
2.一对多 一个部门对应多个员工
3.多对多 一个学生对应多个老师, 一个老师对应多个老师
4.2 一对一封装
4.2.1 表结构封装
说明: 一个员工对应一个部门.
表设计如下:
1.user表:
2. 部门表:
4.2.2 POJO对象封装
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
private Integer id;
private String name;
private Integer age;
//一个员工对应一个部门
private Dept dept;
}
package com.jt.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class Dept implements Serializable {
private Integer deptId;
private String deptName;
}
4.2.3 封装测试方法
package com.jt;
import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class TestMybatis {
private SqlSessionFactory sqlSessionFactory;
@BeforeEach
public void init() throws IOException {
/*创建SqlSessionFactory*/
String resource = "mybatis/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void oneToOne(){
SqlSession sqlSession = sqlSessionFactory.openSession(true);
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = userMapper.selectList();
System.out.println(userList);
}
@Test
public void oneToOne2(){
SqlSession sqlSession = sqlSessionFactory.openSession(true);
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = userMapper.selectList2();
System.out.println(userList);
}
}
4.2.4 编辑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">
<mapper namespace="com.jt.mapper.UserMapper">
<select id="selectList" resultMap="userRM">
select * from user
</select>
<resultMap id="userRM" type="User">
<id property="id" column="id"></id>
<!--如果需要封装单个对象使用association封装-->
<association property="dept" javaType="Dept" column="dept_id" select="selectDeptById"/>
</resultMap>
<select id="selectDeptById" resultMap="deptRM">
select * from dept where dept_id = #{dept_id}
</select>
<resultMap id="deptRM" type="Dept">
<id property="deptId" column="dept_id"></id>
<result property="deptName" column="dept_name"></result>
</resultMap>
<select id="selectList2" resultMap="userRM2">
SELECT u.id,u.name,u.age,d.dept_id,d.dept_name FROM
USER u
LEFT JOIN
dept d
ON
u.dept_id = d.dept_id
</select>
<resultMap id="userRM2" type="User" autoMapping="true">
<!--结果集自动映射-->
<association property="dept" javaType="Dept">
<id property="deptId" column="dept_id"></id>
<result property="deptName" column="dept_name"></result>
</association>
</resultMap>
</mapper>
4.3 一对多封装
4.3.1 封装POJO对象
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class Dept implements Serializable {
private Integer deptId;
private String deptName;
//一个部门下有多个用户.
private List<User> lists;
}
4.3.2 编辑测试文件
@Test
public void oneToMore(){
//自动提交事务
SqlSession sqlSession = sqlSessionFactory.openSession(true);
DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
List<Dept> list = deptMapper.findAll();
System.out.println(list);
sqlSession.close();
}
/*使用子查询的方式获取数据*/
@Test
public void oneToMore2(){
//自动提交事务
SqlSession sqlSession = sqlSessionFactory.openSession(true);
DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
List<Dept> list = deptMapper.findAll2();
System.out.println(list);
sqlSession.close();
}
4.3.3 编辑xml映射文件
<mapper namespace="com.jt.mapper.DeptMapper">
<select id="findAll" resultMap="deptRM">
SELECT d.dept_id,d.dept_name,u.id,u.name,u.age
FROM dept d,USER u
WHERE u.dept_id = d.dept_id
</select>
<resultMap id="deptRM" type="Dept">
<id property="deptId" column="dept_id"></id>
<result property="deptName" column="dept_name"></result>
<collection property="lists" ofType="User" autoMapping="true">
<!--<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="age" column="age"></result>-->
</collection>
</resultMap>
<!--使用关联查询的方式获取数据-->
<select id="findAll2" resultMap="deptRM2">
select * from dept
</select>
<resultMap id="deptRM2" type="Dept">
<id property="deptId" column="dept_id"></id>
<result property="deptName" column="dept_name"></result>
<collection property="lists" ofType="User" column="dept_id" select="findUser"></collection>
</resultMap>
<select id="findUser" resultType="User">
select * from user where dept_id = #{dept_id}
</select>
</mapper>
4.3.4 Mapper映射文件包扫描
说明: 编辑mybatis-config.xml配置文件 通过package属性定义配置信息
要求: 包路径必须与mapper接口的路径相同
<mappers>
<package name="com.atguigu.mybatis.mapper"/>
</mappers>
4.4 延时加载测试
4.4.1 延时加载配置
说明: 如果在进行子查询时 如果不需要立即获取子查询数据 则可以使用懒加载
配置: 编辑mybaits-config.xml配置文件
<settings>
<!--开启驼峰映射 字段dog_id 可以自动映射到 dogId -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
注意事项:
如果没有查询子数据时,则子查询不会执行
@Test
public void testFind2(){
DogMapper mapper = sqlSession.getMapper(DogMapper.class);
List<Dog> list = mapper.selectDog();
list.get(0).getDogName();
//其中list.toString 中调用了子对象 所以会进行子查询
System.out.println(list);
}
4.4.2 立即查询操作
- fetchType=“eager” 懒加载失效
- fetchType=“lazy” 懒加载有效
<!--
mybatis where条件子查询
-->
<select id="selectDog" resultMap="dogSelectRM">
select * from dog
</select>
<!--
select: 执行子查询的操作
column: 主表与从表的关联字段
-->
<resultMap id="dogSelectRM" type="Dog" autoMapping="true">
<id property="dogId" column="dog_id"/>
<association property="dept" javaType="Dept" select="selectDept" column="dept_id" fetchType="eager"/>
</resultMap>
<!--
子表获取主表中关联字段的值 每次一个
-->
<select id="selectDept" resultType="Dept">
select * from dept where dept_id=#{deptId}
</select>
5 Mybatis 缓存
5.1 缓存概念
如果有大量相同的请求查询数据库,则数据库需要执行多次重复的sql,那么并发压力高,查询效率低. 如果引入缓存机制,则可以极大的提升用户的查询的效率
5.2 Mybatis的缓存
- Mybatis中自身提供了缓存机制,可以极大的提高查询效率.
- Mybatis系统中默认定义了两级缓存: 一级缓存 和 二级缓存
- Mybatis默认条件下只开启一级缓存, 一级缓存是sqlSession级别的, 在同一个sqlSession中查询数据可以共享数据.
- 二级缓存默认开启. 二级缓存是SqlSessionFactory级别. 同一个工厂创建多个sqlSession共享数据.
- Mybatis 也提供了第三方Cache接口,整合第三方缓存(了解)
5.3 一级缓存测试
经过测试发现 业务方法查询了多次,但是Sql语句执行了一次.
/*使用子查询的方式获取数据*/
/*使用子查询的方式获取数据*/
@Test
public void testCache1(){
SqlSession sqlSession = sqlSessionFactory.openSession(true);
DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
List<Dept> list1 = deptMapper.findAll2();
List<Dept> list2 = deptMapper.findAll2();
List<Dept> list3 = deptMapper.findAll2();
//测试结果为true,表示引用对象是同一个.
System.out.println(list1 == list2);
}
5.4 二级缓存测试
5.4.1 开启二级缓存
说明: 通过cache标签可以开启二级缓存
5.4.2 二级缓存测试
/*使用子查询的方式获取数据*/
@Test
public void testCache2(){
SqlSession sqlSession = sqlSessionFactory.openSession(true);
DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
List<Dept> list1 = deptMapper.findAll2();
//只有一级缓存关闭之后,二级缓存才能生效
sqlSession.close();
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
DeptMapper deptMapper2 = sqlSession2.getMapper(DeptMapper.class);
List<Dept> list2 = deptMapper2.findAll2();
sqlSession2.close();
}
5.5 Mybatis 缓存测试
5.5.1 一级缓存测试
说明: Mybatis默认的一级缓存是开启的. 但是在SpringBoot整合之后.每次mapper调用都是一个全新的SqlSession.所以导致一级缓存不生效
解决方案: 添加事务注解 使用同一个SqlSession
package com.jt;
import com.jt.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
@SpringBootTest
public class TestMybatis {
@Autowired
private UserMapper userMapper;
//springboot整合mybatis 开启事务之后一级缓存有效.
//否则每次调用都是一个新的sqlSession
@Test
@Transactional
public void test01(){
userMapper.findAll();
userMapper.findAll();
userMapper.findAll();
}
}
5.5.2 二级缓存测试
说明: 在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">
<mapper namespace="com.jt.mapper.UserMapper">
<!--启用二级缓存-->
<cache></cache>
<select id="findAll" resultType="User">
select * from demo_user
</select>
</mapper>
5.5.3 二级注解缓存写法
说明: 二级缓存写法 xml配置文件和注解写法只能二选一 不能同时生效.
package com.jt.mapper;
import com.jt.pojo.User;
import org.apache.ibatis.annotations.CacheNamespace;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @author 刘昱江
* 时间 2021/5/9
*/
@CacheNamespace
public interface UserMapper {
List<User> findAll();
@Select("select * from demo_user")
List<User> getUserAnno();
}
5.5.4 二级缓存相关配置
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
-
缓存策略:
LRU – 最近最少使用:移除最长时间不被使用的对象。 默认的清除策略是 LRU。
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。 -
flushInterval(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。
-
size(引用数目)属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。
-
eadOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。
5.5.5 关于一级缓存和二级缓存的总结
- 一级缓存SqlSession级别, 在同一个sqlSession内实现数据共享. 默认开启的
- 二级缓存SqlSessionFactory级别. 由同一个SqlSessionFactory创建的SqlSession 实现数据共享. 类似于多线程操作的数据共享.
- 二级缓存的配置: 1. 二级缓存默认全局开启 2.如果需要使用
5.6 Mybatis引入第三方缓存
5.6.1 关于缓存介绍
分布式缓存框架:我们系统为了提高系统并发和性能,一般对系统进行分布式部署(集群部署方式)不适用分布缓存, 缓存的数据在各个服务单独存储,不方便系统开发。所以要使用分布式缓存对缓存数据进行集中管理.ehcache,redis ,memcache缓存框架。Ehcache:是一种广泛使用的开源java分布式缓存。主要面向通用缓存,javaEE 和 轻量级容器。它具有内存和磁盘存储功能。被用于大型复杂分布式web application.这里的三方缓存是作为二级缓存使用的
5.6.2 引入jar包
<!-- Mybatis EHCache整合包 -->
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.1</version>
</dependency>
<!-- slf4j日志门面的一个具体实现 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
5.6.3 编写ehcache.xml配置文件
<?xml version="1.0" encoding="utf-8" ?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<!-- 磁盘保存路径 -->
<diskStore path="D:\atguigu\ehcache"/>
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
<!--
属性说明:
diskStore:指定数据在磁盘中的存储位置。
defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略
以下属性是必须的:
maxElementsInMemory - 在内存中缓存的element的最大数目
maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
以下属性是可选的:
timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大
timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每隔120s,相应的线程会进行一次EhCache中数据的清理工作
memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)
-->
5.6.4 配置Cache标签
<!--使用第三方二级缓存-->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
5.7 逆向工程实现
5.7.1 逆向工程介绍
MyBatis Generator: 简称MBG,是一个专门为MyBatis框架使用者定制的代码生成器,可以快速的根据表生成对应的映射文件,接口,以及bean类。支持基本的增删改查,以及QBC风格的条件查询。但是表连接、存储过程等这些复杂sql的定义需要我们手工编写
文档地址: http://www.mybatis.org/generator/
官方工程地址: https://github.com/mybatis/generator/releases
5.7.2 添加插件
<!-- 控制Maven在构建过程中相关配置 -->
<build>
<!-- 构建过程中用到的插件 -->
<plugins>
<!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.0</version>
<!--允许覆盖原始数据-->
<configuration>
<overwrite>true</overwrite>
</configuration>
<!-- 插件的依赖 -->
<dependencies>
<!-- 逆向工程的核心依赖 -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.2</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
5.7.3 编辑配置文件
说明: 编辑generatorConfig.xml的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!--
targetRuntime: 执行生成的逆向工程的版本
MyBatis3Simple: 生成基本的CRUD(清新简洁版)
MyBatis3: 生成带条件的CRUD(奢华尊享版)
-->
<context id="DB2Tables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!-- 数据库的连接信息 -->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/atweb?serverTimezone=UTC&allowMultiQueries=true&rewriteBatchedStatements=true&characterEncoding=utf-8"
userId="root"
password="root">
<property name="nullCatalogMeansCurrent" value="true"/>
</jdbcConnection>
<!-- javaBean的生成策略-->
<javaModelGenerator targetPackage="com.atguigu.mybatis.bean" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- SQL映射文件的生成策略 -->
<sqlMapGenerator targetPackage="com.atguigu.mybatis.mapper" targetProject=".\src\main\resources">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!-- Mapper接口的生成策略 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.atguigu.mybatis.mapper" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!-- 逆向分析的表 -->
<!-- tableName设置为%号,可以对应所有表,此时不写domainObjectName -->
<!-- domainObjectName属性指定生成出来的实体类的类名 -->
<table tableName="demo_user" domainObjectName="User"/>
<!-- <table tableName="%"/>-->
</context>
</generatorConfiguration>
5.8 关于MybatisGenerator API介绍
5.8.1 新增操作实现
@Test
public void test01(){
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = new User();
user.setId(null);
user.setName(null);
user.setAge(null);
user.setSex("男");
//为所有字段添加数据 包括null值
int rows1 = mapper.insert(user);
//为其中非null数据添加赋值操作 选择性添加
int rows2 = mapper.insertSelective(user);
}
5.8.2 动态修改操作
@Test
public void testUpdate(){
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = new User(152,"李四",15,"男");
mapper.updateByPrimaryKey(user);
User user2 = new User(152,null,null,"男");
mapper.updateByPrimaryKeySelective(user2);
}
5.8.3 删除操作
@Test
public void testDelete(){
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.deleteByPrimaryKey(157);
}
5.8.4 查询操作
@Test
public void testSelectByAge(){
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
UserExample userExample = new UserExample();
//大于等于
//userExample.createCriteria().andAgeGreaterThanOrEqualTo(40);
//age区间
//userExample.createCriteria().andAgeBetween(40,200);
Integer[] ids = new Integer[]{3000,4000,5000};
userExample.createCriteria().andAgeIn(Arrays.asList(ids));
List<User> users = mapper.selectByExample(userExample);
System.out.println(users);
}
6 Mybatis 分页插件
6.1 分页插件介绍
分页查询是业务中常用的操作, mybatis为分页提供了强大的支持 pagehelper
6.2 导入jar包
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
6.3 添加插件
注意分页插件 pagehelper的位置
<!--指定别名-->
<typeAliases>
<!--为指定路径的类型 起别名-->
<!--<typeAlias type="com.atguigu.mybatis.pojo.User" alias="Dog"/>-->
<!--通过定义别名包 则指定别名就是类名 运行时会通过该路径扫描特定的注解-->
<package name="com.atguigu.mybatis.pojo"/>
</typeAliases>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
6.4 分页关键字说明
-
pageSize:每页显示的条数
-
pageNum:当前页的页码
-
index:当前页的起始索引,index=(pageNum-1)*pageSize
-
count:总记录数
-
totalPage:总页数
-
totalPage = count / pageSize;
if(count % pageSize != 0){
totalPage += 1;
}
6.5 分页API 讲解
6.5.1 入门案例
@Test
public void testSelect(){
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
PageHelper pageHelper = new PageHelper();
int pageNum = 1; //第一页
int pageSize = 5;
Page<User> page = PageHelper.startPage(pageNum, pageSize);
List<User> list = mapper.selectAll();
list.forEach(System.out::println);
//分页中的所有数据都在其中
PageInfo<User> pageInfo = new PageInfo<>(list,5);
System.out.println(pageInfo);
}
6.5.2 分页查询
在查询功能之前使用PageHelper.startPage(int pageNum, int pageSize)开启分页功能
pageNum:当前页的页码
pageSize:每页显示的条数
6.5.3 分页对象
在查询获取list集合之后,使用PageInfo<T> pageInfo = new PageInfo<>(List<T> list, int navigatePages)获取分页相关数据
list:分页之后的数据
navigatePages:导航分页的页码数
6.5.4 分页对象详情
分页相关数据
PageInfo{
pageNum=8, pageSize=4, size=2, startRow=29, endRow=30, total=30, pages=8,
list=Page{count=true, pageNum=8, pageSize=4, startRow=28, endRow=32, total=30,
pages=8, reasonable=false, pageSizeZero=false},
prePage=7, nextPage=0, isFirstPage=false, isLastPage=true, hasPreviousPage=true,
hasNextPage=false, navigatePages=5, navigateFirstPage4, navigateLastPage8,
navigatepageNums=[4, 5, 6, 7, 8]
}
pageNum:当前页的页码
pageSize:每页显示的条数
size:当前页显示的真实条数
total:总记录数
pages:总页数
prePage:上一页的页码
nextPage:下一页的页码
isFirstPage/isLastPage:是否为第一页/最后一页
hasPreviousPage/hasNextPage:是否存在上一页/下一页
navigatePages:导航分页的页码数
navigatepageNums:导航分页的页码,[1,2,3,4,5]
更多推荐
所有评论(0)