目录
2.10.0.在测试类中使用测试注解@Before @After减少重复代码
5.使用ThreadLocal优化sqlSession工具类
8.5 映射器 Mappers(将映射文件映射到mybatis配置文件)
9.1.4 对一映射方式2:直接引用关联对象的Mapper映射
9.1.5 对一映射方式3:直接引用关联对象的单独查询的方法
9.2.2 方式2:不使用连接查询+引用关联对象的单独查询的方法
12.2 一级缓存:SqlSession级别的缓存,自动开启
1、Mybatis概述
1.1 JDBC编程
1.2.说说你对Mybatis的了解
1.Mybatis 基于java的持久层框架,它的内部封装了JDBC,让开发人员只需要关注SQL语句本身,不需要花费精力在驱动的加载、连接的创建、Statement的创建等复杂的过程。
1.3 Mybatis解决的问题
1、数据库连接的创建、释放连接的频繁操作造成资源的浪费从而影响系统的性能。
2、SQL语句编写在代码中,硬编码造成代码不容易维护,实际应用中SQL语句变化的可能性比较大,一旦变动就需要改变java类。
3、使用preparedStatement的时候传递参数使用占位符,也存在硬编码,因为SQL语句变化,必须修改源码。
4、对结果集的解析中也存在硬编码。
2、Mybatis入门案例
2.1 创建数据库和表
CREATE TABLE `team` (
`teamId` int NOT NULL AUTO_INCREMENT COMMENT '球队ID',
`teamName` varchar(50) DEFAULT NULL COMMENT '球队名称',
`location` varchar(50) DEFAULT NULL COMMENT '球队位置',
`createTime` date DEFAULT NULL COMMENT '球队建立时间',
PRIMARY KEY (`teamId`)
) ENGINE=InnoDB AUTO_INCREMENT=1003 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
2.2 创建maven项目,添加Mybatis的jar依赖
创建个java的maven项目
2.3 编写Mybatis的配置文件
一般情况下:配置文件的名称可以自定义,使用mybatis.xml。配置文件放置在java/resources中。
头文件去官网中复制粘贴。提供一个中文的网站。Mybatis网址
配置文件中配置mybatis的环境(数据源、事务类型)
2.4 编写实体类
实体类中的属性必须与表中的列名保持一致,默认构造+set+get(不能少)
2.5 编写ORM映射文件
我们是针对实体类Team.java和表Team进行ORM映射.
2.5.1 XML映射文件必须与实体类在同一个包下面
2.5.2 XML映射文件名称必须是实体类名称一致
头文件在网站复制即可。Mybatis网址
注意namespace、id、resultType分别表示什么。
2.6 将映射文件注册到mybatis的配置文件中
2.7 配置映射文件的扫描位置
2.8 使用Mybatis框架的核心接口测试
2.9. 配置日志文件
2.9.1.添加jar依赖
2.9.2.添加日志配置文件
# Global logging configuration info warning error
log4j.rootLogger=DEBUG,stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
2.9.3.在mybatis配置文件中添加日志的配置
2.10.入门案例的增删改查
2.10.0.注意:手动提交事务
增删改操作,必须手动提交事务,否则不生效
因为上面在mybatis配置中,指定了JDBC方式(Connection)管理事务,默认自动提交是false,
解决1.每执行一次增删改sql,我们手动提交sqlSession.commit()
解决2.在获取sqlSession会话时,开启自动事务,参数true,即factory.openSession(true)
这只是在dao层操作事务,不推荐,将来事务都是在service层通过声明式事务管理
实体类
2.10.0.在测试类中使用测试注解@Before @After减少重复代码
2.10.1 根据ID查询单个对象
parameterType:参数类型,sql中占位符类型,该属性基本类型时可省略,实体类型则不可省略
resultType:返回类型,执行这条sql后返回什么类型的结果,基本类型可省略不写,若集合则其元素类型-->
报错原因:实体类没有加默认构造方法
Team.xml的映射文件中添加:
测试类中添加如下内容:
2.10.2 增删改
2.10.3.查询所有
映射文件添加
测试类添加
3、Mybatis对象分析
3.1 Resources
3.2 SqlSessionFactoryBuilder
SqlSessionFactoryBuilder 充当的就是建造者角色 ,sqlSession就是我们最后得到的产品。
3.3 SqlSessionFactory
3.4 SqlSession
selectOne 和 selectList 的不同仅仅是 selectOne 必须返回一个对象或 null 值。如果返回值多于一个,那么就会抛出异常。
3.5 Mybatis架构/工作流程
4、原有的Dao方式开发
4.1 创建sqlSession工具类
4.2 创建TeamDao接口和实现类
测试:
sql映射文件Team.xml
结果
5.使用ThreadLocal优化sqlSession工具类
5.0.ThreadLocal的理解
5.1.SqlSession线程不安全处理方案
保证多个线程使用的sqlSession是相互独立的,没有关联,若A、B使用同一个sqlSession,若A使用完close关闭sqlSession,那么B就无法执行了。可以给每一个线程绑定一个副本的sqlSession,这就需要使用ThreadLocal。
优化后的工具类
6、使用Mapper的接口编写Mybatis项目
6.1 什么是Mapper接口
6.2 使用Mapper动态代理
注意,通过Mapper接口 的动态代理帮我们生成了接口实现类,接口的方法要与映射文件中的对应的id名称一致,否则无法定位到指定的sql。
6.2.1 编写接口TeamMapper.java
在mybatis.xml配置文件中注册映射文件
6.2.2 getMapper方法获取代理对象
只需调用 SqlSession 的 getMapper()方法,即可获取指定接口的实现类对象。
6.3 实现原理
Mapper接口的动态代理是如何在程序运行期间帮我们创建接口的实现类对象的?
我们是通过SqlSession 的 getMapper()方法获取到了接口的实现类对象,该方法是基于jdk的动态代理在程序运行的时候代理我们创建接口对象,就是通过Proxy.newProxyInstance()方法进行的动态代理,第一参数传递类加载,第二个参数传递接口类集合,第三个参数回调程序编写代理规则,在这里代理生成接口实现类。
7、增删改查中的细节
7.1 插入数据的时候返回自增的id值
即我们将一个对象插入数据库中时,是不提供主键id的值得,id自增自动赋值,那么现在希望插入数据后返回这条数据的id值?
7.1.1.返回Integer类型的自增id值
Team实体类
TeamMapper接口(只是用add)
TeamMapper.xml映射文件(只看add)
注册TeamMapper.xml映射文件到mybatis配置文件
测试
7.1.2.返回字符串类型的自增id值
添加一张新表:球队记录表
CREATE TABLE `gamerecord` (
`recordId` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`homeTeamId` int DEFAULT NULL COMMENT '主队ID',
`gameDate` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '比赛日期',
`score` int DEFAULT NULL COMMENT '得分',
`visitingTeamId` int DEFAULT NULL COMMENT '客队ID',
PRIMARY KEY (`recordId`) USING BTREE,
KEY `homeTeamId` (`homeTeamId`) USING BTREE,
KEY `visitingTeamId` (`visitingTeamId`) USING BTREE,
CONSTRAINT `gamerecord_ibfk_1` FOREIGN KEY (`homeTeamId`) REFERENCES `team` (`teamId`) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT `gamerecord_ibfk_2` FOREIGN KEY (`visitingTeamId`) REFERENCES `team` (`teamId`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;
实体类:球队记录实体类
mapper接口GameRecordMapper
映射文件GameRecordMapper.xml,添加selectKey节点
测试
7.2 输入映射(传参到sql)
7.2.0.parameterType只能接收一个参数
接收的是基本类型(Integer/String..)的话是可以省略parameterType该属性、若是实体类对象,那么sql中占位符位置必须是实体类中属性。
7.2.1.使用下标方式#{arg0}或#{param1}
实体类还是Team
mapper接口还是TeamMapper,新添加方法
TeamMapper.xml配置文件中添加如下:
测试类添加方法:
7.2.2.通过@Param注解传递多个传参
测试
TeamMapper.xml配置文件中添加如下
测试类添加方法:
7.2.4. 通过pojo类传递多个参数
与map传递多个参数类似,要求映射文件中的参数占位符必须和pojo类中的属性完全一致。
自己封装的查询条件的类
TeamMapper接口添加如下内容:
测试
总结:
7.3 #{} 和 ${}的区别--面试中喜欢出的考题
7.3.2 ${}
teamMapper.xml
测试
方拾二:sql中使用${}代替列名,使用不同列作为查询条件
teamMapper接口
teamMapper.xml测试
7.4 输出映射resultType
7.4.0.输出pojo类型
7.4.1.输出简单类型(单行单列)可省
如果查询sql返回的是简单类型且是单行单列(只要一个值)。resultType写值得类型或可以省略
teamMapper.xml映射文件
测试
7.4.2.输出map集合类型(单行多列)
teamMapper接口
teamMapper.xml映射文件
测试
7.4.3.输出List集合类型(多行多列)
输出list集合类型--当返回多行多列时使用,list中元素是map,每个map描述一条记录
teamMapper接口
teamMapper.xml
测试
7.5. 输出映射resultMap
当使用resultType="com.chen.pojo.Team"返回Team对象时,mybatis会把sql查询结果自动映射到Team对象中,前提是Team属性与表的列名是一致的,那么当不一致时,这样写就会报错,这时就需要使用resultMap去自定义表和实体类的映射关系 。
teamMapper接口
teamMapper.xml映射文件
测试
7.6. 数据库表中列与实体类属性不一致的处理方式
CREATE TABLE `users` (
`user_id` int NOT NULL AUTO_INCREMENT COMMENT '用户id',
`user_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '用户姓名',
`user_age` int DEFAULT NULL COMMENT '用户年龄',
PRIMARY KEY (`user_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;
7.6.1.使用列别名和resultType
7.6.2.使用resultMap
8、Mybatis的全局配置文件
<?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">
8.1 全局配置文件配置的内容
8.2 属性(properties)
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/team?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
jdbc.username=root
jdbc.password=root
8.3 设置 settings
8.4 类型别名 typeAliases
8.4.1 Mybatis中已经支持/内置的别名
8.4.1 Mybatis中已经支持的别名
8.4.2 自定义别名
对于自定义的类,我们可以给其起个别名
在配置文件配置别名,注意查看<typeAliases>该放在哪个位置,通过
<configuration>进入查看配置顺序
可以直接使用别名替代全类名
8.5 映射器 Mappers(将映射文件映射到mybatis配置文件)
8.5.1、 类路径引用映射文件
8.5.2、使用的mapper接口的完全限定名
8.5.3、将包内的映射器接口实现全部注册为映射器--推荐
指定包下的所有Mapper接口
8.6 dataSource标签
8.7 Mybatis如何管理事务
8.7.1、默认是需要手动提交事务的
managed:由容器来管理事务的整个生命周期(如Spring容器)。
8.7.2、自动提交事务
9、Mybatis中的关系映射
就是如何给一个实体类中基本属性以及关联属性(对象/list集合)去映射查询的结果,通常是一对多关系的两表连接查询中遇到。
或者说对一/对多关系的结果映射的处理方式有哪些
球队与球员关系:一对多关系
一个球队有多个球员
一个球员属于一个球队
在java中球员如何实现多对一的关系的绑定,在mybatis中又是如何进行对一关系的映射?
在java中球队如何实现一对多的关系的绑定,在mybatis中又是如何进行对多关系的映射?
连接查询的结果集(查询球员信息包含所在球队信息)在mybatis中是如何映射到实体类的?
9.1 对一关系映射的处理方式(三种方式)
9.1.0.需求:查询球员信息包含所在球队信息
9.1.1 实体类
添加关联字段Team球队对象
9.1.2 mapper接口
9.1.3 对一映射方式1:通过关联对象打点调用属性的方式
方式1:对一关系的映射:两表的连接查询+通过关联对象打点调用属性的方式
PlayerMapper接口
PlayerMapper.xml
baseResultMap映射
9.1.4 对一映射方式2:直接引用关联对象的Mapper映射
PlayerMapper.xml 映射文件
resultMap所继承当前映射文件中的baseResultMap
resultMap所引用的TeamMapper映射文件中的baseResultMap
测试
9.1.5 对一映射方式3:直接引用关联对象的单独查询的方法
要求:1、不需要两表的连接查询 ,拆开查询
2、关联对象中已经存在被引用的查询方法
同上,这里只展示映射文件添加的内容:
9.1.6 测试
9.2 对多关系的结果映射的两种处理方式
9.2.0.查询球队信息以及拥有的球员信息
Team球队实体类 添加关联字段List集合存储球队的球员
9.2.1 方式1:连接查询+引用关联对象的结果映射
TeamMapper接口添加方法
TeamMapper.xml映射文件
测试
9.2.2 方式2:不使用连接查询+引用关联对象的单独查询的方法
先在PlayerMapper接口中定义根据teamId查询球员的方法
PlayerMapper.xml映射文件中
TeamMapper接口定义方法
TeamMapper.xml映射文件
测试
10、Mybatis动态SQL
Mybatis使用标签构建动态SQL语句
10.1 where标签构建动态SQL多条件查询
10.1.1.原有写法:根据不同条件拼接 SQL 语句
10.1.2.where标签构建动态SQL多条件查询
TeamMapper.xml映射文件添加:
测试
10.2 set标签构建动态sql的更新update
10.2.1 原有的更新存在的弊端
当前台只是更新team中几个属性,会导致team其它属性数据丢失
TeamMapper接口
TeamMapper.xml映射文件
测试
TeamMapper接口
TeamMapper.xml映射文件
测试
10.3 forEach标签构建动态sql的批量添加/删除
10.3.1 批量添加
TeamMapper接口
TeamMapper.xml映射文件
测试
10.3.2 批量删除
TeamMapper接口
TeamMapper.xml映射文件
测试
11 、分页插件
11.1 jar依赖
11.2 在Mybatis全局配置文件中添加插件配置
mybatis中的配置都是有顺序要求的
11.3 使用插件
12、Mybatis缓存
12.1 缓存作用
12.2 一级缓存:SqlSession级别的缓存,自动开启
12.2.1 一级缓存工作原理
12.2.2 清空缓存的方式
手动清空/执行增删改并提交后自动清空/关闭会话/xml中刷新缓存/提交回滚都会清空缓存
12.3 二级缓存:Mapper级别的缓存
12.3.0.二级缓存工作原理
12.3.1 使用二级缓存步骤
1.在mybatis配置文件中开启二级缓存
2.在需要二级缓存的Mapper中添加缓存标记
3.实体类必须实现Serializable接口
因为缓存是需要写入数据的
12.3.2 二级缓存的禁用
当在Mapper映射文件中使用了二级缓存,那么该映射文件中所有的select语句都会启用缓存,我们可以去禁用某个sql查询。
12.3.3 缓存的属性配置
缓存中有哪些属性
如果想在命名空间中共享相同的缓存配置和实例,可以使用cache-ref 元素来引用另外一个缓存
<cache-ref namespace="com.kkb.mapper.TeamMapper" />
13、反向生成插件
13.0.反向生成几个注意点
根据单表反向生成这些内容,包括单表的最基本的增删改查、还有接口、映射文件,包括动态查询,动态的插入更新,多条件查询都写好了,只要是单表操作,都给我们生成了,我们只需要引用方法就可以了,sql语句都写好的。
同一张表只能一次反向生成,除非删除掉之前生成的内容,不然再一次反向生成的内容会追加的,比如出现两个BaseResultMap。
如果其它数据库有相同的表,也会被反向生成的
13.1 插件的配置
<?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">
<!-- 配置生成器 -->
<!--注意:
1.同一张表只能一次反向生成,除非删除掉之前生成的内容,不然再一次反向生成的内容会追加的,比如出现两个BaseResultMap
2..如果其它数据库有相同的表,也会被反向生成的-->
<generatorConfiguration>
<!--1、数据库驱动jar:添加自己的jar路径 -->
<classPathEntry location="E:\mysql8.0驱动程序\mysql-connector-java-8.0.16.jar" />
<context id="MyBatis" targetRuntime="MyBatis3">
<!--去除注释 -->
<commentGenerator>
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--2、数据库连接 -->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://127.0.0.1:3306/team?useUnicode=true&characterEncoding=utf-8&
useSSL=false&serverTimezone=GMT" userId="root" password="64531515z">
</jdbcConnection>
<!-- 默认false,把JDBC decimal 和 numeric 类型解析为 Integer;
为 true时把JDBC decimal和numericC类型解析为java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!--3、生成实体类 指定包名 以及生成的地址 (可以自定义地址,但是路径不存在不会自动创建 使用Maven生成在target目录下,会自动创建)-->
<javaModelGenerator targetPackage="org.bowei.pojo" targetProject="src\main\java">
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!--4、生成SQLmapper.xml映射文件 -->
<sqlMapGenerator targetPackage="org.bowei.mapper" targetProject="src\main\resources"> </sqlMapGenerator>
<!--5、生成Dao(Mapper)接口文件,-->
<javaClientGenerator type="XMLMAPPER" targetPackage="org.bowei.mapper" targetProject="src\main\java"> </javaClientGenerator>
<!--6、要生成哪些表(更改tableName和domainObjectName就可以) -->
<!-- tableName:要生成的表名
enableCountByExample:Count语句中加入where条件查询,默认为true开启
enableUpdateByExample:Update语句中加入where条件查询,默认为true开启
enableDeleteByExample:Delete语句中加入where条件查询,默认为true开启
enableSelectByExample:Select多条语句中加入where条件查询,默认为true开启
selectByExampleQueryId:Select单个对象语句中加入where条件查询,默认为true开启 -->
<!--
<table tableName="Team"
enableCountByExample="false"
enableUpdateByExample="false"
enableUpdateByPrimaryKey="false"
enableDeleteByExample="false"
enableDeleteByPrimaryKey="false"
enableSelectByExample="false"
selectByExampleQueryId="false">
<property name="useActualColumnNames" value="true"/>
</table>
-->
<!--根据表反向生成这些内容,包括
单表的最基本的增删改查、还有接口、映射文件,包括动态查询,多条件查询都写好了,只要是单表操作,我们就不需要动,只需要选择要用的-->
<table tableName="Users">
<!--表不区分大小,比如表字段teamId,由表生成的实体类属性是teamid,下面设置就是针对这个问题-->
<property name="useActualColumnNames" value="true"/>
</table>
</context>
</generatorConfiguration>
我们只需要提供数据表,以及反向生成插件和配置即可。
生成后检查映射文件中只有一个ResultMap就表示生成正常,没有同名的表被生成。可以看到生成的映射文件中你能想到的所有单表查询的sql都写好了,包括动态的更新、插入(即对象中属性不全都有值),多条件查询等,我们只需要引用id名即可。
13.2 使用反向生成中的多条件查询方法