Mybatis简介
MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
解决dao层问题解决方案, 之前dao使用的技术: JDBC
问题:
1,Sql语句硬编码在代码中, 如果修改sql, 重新编译
2.JDBC步骤固定, 如果执行多次sql, 重写编写相同的代码,
3.数据源参数硬编码
mybatis入门程序
1.添加依赖: mybatis, 数据库驱动(mysql), junit测试
Mysql驱动:
5版本: 驱动类: com.mysql.jdbc.Driver
8版本: 驱动类: com.mysql.cj.jdbc.Driver, 指定时区
mysql安装 5.7 开源免费的版本
Oracle收购mysql: 从8开始, 有oracle相关的功能, 社区版(免费的), 专业版(收费)
2.在项目下创建Mybatis全局配置文件: mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
3.在该配置文件创建一个数据源:
<!--开发环境-->
<environments default="mysql">
<environment id="mysql">
<!--事务管理器: JDBC: 使用jdbc管理事务, 需要手动提交事务-->
<transactionManager type="JDBC"/>
<!--dataSource数据源的类型: POOLED 连接池 UNPOOLED: 不带连接池 -->
<dataSource type="POOLED">
<!--数据库四大参数-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="123"/>
</dataSource>
</environment>
</environments>
</configuration>
- 创建表对应的实体类
使用lombok插件: 自动生成get/set 构造方法, toString hashCode
- 编写sql映射文件 实体类名Dao.xml 或者 实体类名Mapper.xml
- 在mybatis的全局配置文件中,加载sql映射文件
- 编写代码实现查询 后期都不写 测试代码
日志框架
在控制台打印sql语句, mybatis的执行的日志, 方便开发调式
需要使用日志框架: log4j
- 添加log4j的依赖
<!--log4j-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.36</version>
</dependency>
2.添加log4j的配置文件 log4j.properties
#在开发阶段使用debug,在生产环境设置为info或者error
# 日志输出级别: 从低到高: debug < info < warn(警告) < error(错误)
# 设置的级别debug, 输出级别比它都会输出
log4j.rootLogger=debug,console
#控制台输出 ConsoleAppender: 输出目的地: 控制台
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d %p [%c] - %m%n
Mybatis的Mapper代理模式
底层使用的是动态代理: 通过代码,运行时,动态生成某个类,某个接口的代理类(不存在)对象
传统Dao模式:
Dao接口, Dao实现类 : 方法有大量相似的代码, 有代码重复
分析原因:
Dao实现类存在
解决方案: 删除Dao实现类, 创建Dao对象
使用动态代理,动态生成Dao对象
对接口中所有的抽象方法,提供实现(方法体完成)
Mapper代理实现的要求:
1.sql映射文件的namespace必须是对应Dao接口的全限定名(包.接口名)
2.sql映射文件的Statement的id必须是对应方法的方法名
实现方法
1.编写一个Mapper接口(Dao接口)
2.编写对应的Sql映射文件: 满足Mapper代理实现的要求
3.一个Mapper接口对应一个sql映射文件
service类怎么得到Mapper接口代理对象?
SqlSession的getMapper(Class clazz): 根据传递Mapper接口类型,得到对应Mapper接口代理对象
Mapper方法多个参数
#{名字} 名字
使用arg0,arg1 …
使用param1, param2….
在Mapper方法上使用注解指定参数名:@Param 指定名字
Mybatis细节
面试高频, 注意
#{}使用?占位 推荐
${}拼接sql, 有sql注入风险
selectOne 与selectList 面试
selectOne底层使用selectList
selectOne() 如果结果集记录数>1, 抛TooManyResultsException异常
selectList() 结果集记录可以是1条,可以多条,可以没有
selectOne都可以被selectList替换
添加细节
使用 last_insert_id()函数
#查询到生成id mysql提供的系统函数 LAST_INSERT_ID()
前提: insert与LAST_INSERT_ID 必须在同一次会话(session)中
InputStream, SqlSessionFactoryBuilder,SqlSessionFactory,SqlSession 的scope作用域:
InputStream, SqlSessionFactoryBuilder:
一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域
方法的局部变量
SqlSessionFactory
SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次
作为静态属性
SqlSession
每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域
方法的局部变量
动态sql
sql语句是变化, 根据用户输入的结果,产生不同sql语句
使用场景:
1.动态排序 ${}
2.动态条件 用户在网页端根据需求添加条件, 后台根据用户输入条件动态生成对应sql
3.条件个数不确定
4.条件内容不确定
5.前端提供了n个条件, 用户根据需求随机组合
Mybatis提供支持动态sql的实现:
提供了动态sql标签:
if: if条件
where: where关键字
foreach: 循环标签
set: set关键字
sql: sql片段, 重复sql的重用
表连接查询
<select id="selectOrderAndUserById" parameterType="int" resultMap="orderUserMap">
select u.*, o.id oid, o.createtime, o.state, o.userid
from tb_user u
join tb_order o
on u.id = o.userid
where o.id = #{id}
</select>
<resultMap id="orderUserMap" type="Order">
<id property="id" column="oid"></id>
<result property="userId" column="userId"></result>
<result property="createTime" column="createTime"/>
<result property="state" column="state"/>
<!--单个关联属性 association
property: 属性名
javaType: 数据的数据类型
-->
<association property="user" javaType="User">
<id column="id" property="id"/>
<!--非主键映射-->
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="sex" property="sex"/>
<result column="brithday" property="brithday"/>
<result column="address" property="address"/>
</association>
</resultMap>