- MyBatis简易教程
- 1. 准备工作
- 2. XML配置方式示例
- 3. 代码配置方式示例
- 4. MyBatis扩展
- 5. MyBatis缓存
- 6. 批量操作、分库分表、读写分离
- 7. mybatis-plus
- 参考
总结MyBatis的知识点
MyBatis简易教程
示例项目:mybatisdemo
1. 准备工作
1.1 创建测试数据库及表
create database testdb;
use testdb;
CREATE TABLE `user` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20),
`age` INT,
`birthday` DATE,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8;
1.2 项目添加MyBatis maven依赖
https://mvnrepository.com
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
1.3 Mybatis XML配置
mybatis-config.xml //名称可以定制,可以配置多个环境
jdbc.properties //可以通过引用properties文件将数据库连接配置独立出来
详细配置节点参考官方配置说明
1.4 日志输出配置
通过settings节点配置日志输出组件,示例中使用log4j2
mybatis-config.xml中日志配置
<settings>
<setting name="logImpl" value="LOG4J2"/>
</settings>
添加log4j2日志依赖
<!--为了查看mybatis输出的日志信息包括sql语句,使用log4j2来打印日志-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j2-version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j2-version}</version>
</dependency>
添加log4j2的配置文件log4j2.xml,log4j2的配置文件节点参考官方配置说明
2. XML配置方式示例
2.1 添加数据库实体模型
User.java
2.2 添加数据库操作接口
UserMapper.java
2.3 添加XML映射文件(数据库操作类<==>sql)
动态sql映射文件UserMapper.xml,动态sql的语法参考官方说明文档,这里不详细讲
注:
a) UserMapper.java与UserMapper.xml一般保持命名空间一致
b) mybatis-config.xml中需要配置UserMapper.xml,MyBatis通过该配置动态生成数据库操作接口对应实现类
c) xml文件在编译时可能没有被默认加入到resources目录,所以需要在pom文件中build>resources节点显式将xml文件include到resources目录下
d) 如果模型字段名称和数据字段名称不一致,可以通过resultMap节点指定映射关系
2.4 添加获取SqlSession封装工具类
MyBatisUtil.java
该工具类的作用:
a) 通过createSqlSessionFactoryFromXML方法根据XML配置文件mybatis-config.xml初始化SqlSessionFactory
b) 获取SqlSession对象
2.5 测试
新建App.java,添加增删改查一共5个测试方法
public static void insertUser();
public static void deleteUser();
public static void updateUser();
public static void selectUserById();
public static void selectAllUsers();
3. 代码配置方式示例
通过本地xml、properties文件的配置方式在公司内部使用时可能会有很多限制:
a) 运维部门可能不允许线上直接修改本地配置文件,需要接入配置中心统一管理
b) 线上应用是分布式发布,多台机器手工修改配置文件不太现实
再加上约定大于配置、去配置文件是一个趋势,通过code方式进行配置也是不可缺少的
3.1 添加code配置
MyBatisUtil.java工具类中可以直接进行配置,createSqlSessionFactoryFromCode方法将帮助你使用code方式来进行配置,这时候mybatis-config.xml配置文件就可以丢弃了(包括独立出来的jdbc.properties文件)。
注:
a) log4j.xml日志配置文件在使用本地配置的时候可以保留,但如果接入公司日志中心平台,也可以通过code方式去除,通过自定义appender将日志写入到日志中心平台
b) 同样的,需要指定mapper.xml映射文件的地址,可以通过Configuration.addMappers(String packageName)方法通过包名批量添加
MyBatisUtil.java中切换createSqlSessionFactoryFromCode方法初始化SqlSessionFactory之后,之前的5个测试方法同样生效
3.2 如何将动态sql映射文件UserMapper.xml一并去除?
动态sql功能很强大,统一维护到xml映射文件中管理也很方便,但是可以做到0配置文件吗?
MyBatis提供了annotation机制,可以在数据库操作接口UserMapper中直接通过annotation来直接编写sql语句,对于非常复杂的sql,也可以通过SqlProvider来将复杂sql语句处理独立出来
示例见UserMapper.java中以下两个方法:
@Select("select * from user where " +
"name like concat('%',#{searchKey},'%') " +
"limit #{offset},#{limit}")
List<User> searchByName(@Param("offset")int offset, @Param("limit") int limit, @Param("searchKey")String searchKey);
@SelectProvider(type=CustomSqlProvider.class,method = "searchUsersByName")
List<User> searchByNameWithSqlProvider(String searchKey);
执行效果跟在mapper.xml中写动态sql是一样的
注: a) 如果模型字段名称和数据字段名称不一致,可以通过@Results指定映射关系
b) 不建议直接通过字符串拼接的方式写sql,通过参数化的方式可以避免sql注入问题 c) 使用annotation写sql的方式与在mapper.xml中写sql的方式可以混合用,MyBatis官方建议复杂查询(例如嵌套join)还是使用mapper.xml,建议简单sql使用annotation,复杂sql使用mapper.xml,或者项目中统一使用mapper.xml来统一管理sql,性能上的差异没有看到过比较,你可以自己测试一下
4. MyBatis扩展
4.1 拦截器,自动分页拦截器
项目中实现org.apache.ibatis.plugin.Interceptor接口创建示例分页拦截器PageInterceptor.java,该拦截器只要发现查询参数类型为Page,就执行自动分页操作
在MyBatisUtil.java中通过Configuration.addInterceptor(Interceptor interceptor)方法添加分页拦截器
数据库操作接口UserMapper中添加自动分页操作方法
@SelectProvider(type=CustomSqlProvider.class,method = "autoPagedQuery")
List<User> autoPagedQuery(Page<User> pageCondition);
App.java中的测试方法
/**
* 利用分页拦截器来进行sql语句的自动分页查询
* 【注意】:本示例中仅在通过code的方式创建session factory时才有效, 通过读取mybatis-config.xml的方式没有配置分页拦截器
*/
private static void autoPagedQuery();
拦截器的其它信息可以参考官方文档
4.2 代码生成器
数据库添加测试表
use testdb;
CREATE TABLE `user_address` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`user_id` INT(11) NOT NULL,
`address` varchar(256),
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8;
pom添加mybatis生成器插件
<dependencies>
<!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.5</version>
</dependency>
<!--其它依赖-->
</dependencies>
<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.5</version>
<configuration>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</plugin>
<!--其它插件-->
</plugins>
添加生成器指定的配置文件generatorConfig.xml,详细配置见说明,这里指定只生成刚才创建的user_address表对应的实体模型、数据库操作接口、映射mapper.xml文件
生成器需要用到sql驱动,需要在jdbc.properties中指定驱动jar包地址
jdbc.driverLocation=C:\\Users\\Administrator\\.m2\\repository\\mysql\\mysql-connector-java\\6.0.6\\mysql-connector-java-6.0.6.jar
点击idea右侧maven>Plugins>mybatis-generator>mybatis-generator:generate
,或者项目中命令执行mvn命令mvn: mybatis-generator:generate
注:
生成器只是一个辅助工具,不建议正式项目中添加生成器,多人使用时由于使用不当,可能会造成代码覆盖等问题
5. MyBatis缓存
5.1 介绍
MyBatis提供了一级缓存(Session级别缓存,默认开启)和二级缓存(Mapper级别缓存,可以跨Session,需要mapper.xml中配置)
网上搬运过来的介绍
a). 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。
b). 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。
c). 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。
注:
排除特殊场景,个人认为没有必要在实际项目中使用二级缓存或者自定义缓存
建议使用分布式缓存框架(例如redis),或者本地缓存框架(例如ehcache)根据实际业务场景自己控制缓存
5.2 一级缓存
通过App.java中一级缓存测试方法测试,观察输出的sql判断是否结果被缓存
private static void testCache1();
5.3 二级缓存
在mapper.xml中配置cache节点
<cache
eviction="FIFO" <!--回收策略为先进先出-->
flushInterval="60000" <!--自动刷新时间60s-->
size="512" <!--最多缓存512个引用对象-->
readOnly="true" /> <!--只读-->
通过App.java中一级缓存测试方法测试,观察输出的sql判断是否结果被缓存
private static void testCache2();
开启mapper.xml中二级缓存之后,指定其中某个查询不使用缓存也是可以的
<select id="xxx" resultMap="xxx" useCache="false" />
5.4 自定义缓存
实现org.apache.ibatis.cache.Cache
接口来自定义缓存,mapper.xml中配置<cache type="自定义缓存类全路径" />
来指定使用缓存
6. 批量操作、分库分表、读写分离
6.1 批量操作 & 多表关联查询
annotation: 配合script标签+foreach
复杂sql使用SqlProvider
//示例
public interface MybatisDemoDAO {
@Insert({
"<script>",
"insert into mybatis_demo (name, age)",
"values ",
"<foreach collection='dmoList' item='dmo' separator=','>",
"( #{dmo.name,jdbcType=VARCHAR}, #{dmo.age,jdbcType=INTEGER})",
"</foreach>",
"</script>"
})
int insertBatch(@Param("dmoList") List<MybatisDemoDMO> dmoList);
}
多表关联查询
Advanced Result Maps - association
6.2 分库分表拦截器
6.3 MyBatis + sharding-jdbc
参考:sharding-jdbc + mybatis +spring boot的分库分表实现