文章目录
MyBatis简介
. Mybatis 开源免费框架,是数据库访问层的框架,底层是对JDBC的封装
在使用MyBatis时不需要编写实现类,只需要写写sql命令。这是MyBatis的一个优点
环境搭建
导入jar包
导入MyBatis的jar包和MySQL的驱动包
其中
其中这是核心包
asm为Cglib的依赖包
cglib为动态代理包
commons-loggiing为日志包
javaassist为字节码解析包,也是cglib依赖的包
log4j都为日志包
slf4j也为日志包
建立配置文件
1.首先在src下建立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">
<configuration>
<environments default="default">
<!--defaulty引用environment的id,表示当前所使用的环境-->
<environment id="default">
<!--使用JDBC原生事务-->
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOlED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/db_contracts?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers> <!--于之后的建立的mapper映射文件建立联系-->
<mapper resource="cn/com/mapper/UserMapper.xml" />
</mappers>
</configuration>
2.新建映射文件
<?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="cn.com.mapper.UserMapper">
<select id="selectAll" resultType="cn.com.pojo.User">
select * from user
</select>
</mapper>
可以将namespace理解为全路径(包名+类名)
将id理解为方法名
resultType为返回值类型
如果方法返回值是 list,在 resultType 中写 List 的泛型, 因为 mybatis 对 jdbc 封装,一行一行读取数据
3.调用获取结果
package cn.com.test;
import cn.com.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 java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class Test {
public static void main(String[] args) throws IOException {
//获取流数据
InputStream is= Resources.getResourceAsStream("MyBatis.xml");
//创建工厂
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is);
//生产SqlSession
SqlSession sqlSession=factory.openSession();
//查询结果
List<User> list=sqlSession.selectList("cn.com.mapper.UserMapper.selectAll"); //使用namespace的路径+mapper标签的id
for (User u:list){
System.out.println(u);
}
}
}
解析配置文件
在全局配置文件MyBatis.xml中
<transcationManager>标签中Type属性可取值为
1:JDBC,表示事务管理使用JDBC原生事物管理方式
2:MANAGED,表示事务管理转交给其他容器。原生JDBC事务的setAutoMapping(false)
<dataSouce>标签中Type属性
1:POOLED 使用数据库连接池
2.:UNPOOLED 不使用数据库连接池,和原生JDBC一样
3:JNDI java命名目录接口技术
MyBatise原理
获取SqlSession原理
InputStream is= Resources.getResourceAsStream("MyBatis.xml");
//创建工厂
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is);
//生产SqlSession
SqlSession sqlSession=factory.openSession();
这是创建SqlSession的步骤,为什么要使用SqlSessionFactoryBuilder来创建工厂而不直接创建工厂呢?
因为直接创建太过繁琐
SqlSessionFactory是一个接口,所以实例化时需要创建其实现类DefaultSqlSessionFactory,但是DefaultSqlSessionFactory的构造方法需要传入Configuration对象。对于Configuration对象并不好创建
所以使用SqlSessionFactoryBuilder的build()方法来创建
进入build的源码可以看出其内部原理
在其内部是使用的XMLConfigBuilder来解析配置文件
然后调用XMLConfigBuilder的parse方法来为build方法传参
而build的参数是Configuration对象所以 可以等效为
InputStream is= Resources.getResourceAsStream("MyBatis.xml");
//获取解析器
XMLConfigBuilder parse=new XMLConfigBuilder(is,null,null);
//获取Configuration对象
Configuration configuration = parse.parse();
//获取SqlSessionFactory工厂
SqlSessionFactory factory=new DefaultSqlSessionFactory(configuration);
//生产SqlSession
SqlSession sqlSession=factory.openSession();
可以比较出SqlSessionFactoryBuilder创建更为简便
openSession
DefaultSqlSessionFactory的openSession中是如何创建session对象
这也可以验证autoCommit默认是false
在openSession()方法中可以看出
1.Transaction 是事务类
2.TransactionFactory 事务工厂 ,负责生产 Transaction
3.Executor MyBatis 执行器
作用:负责执行 SQL 命令 ,相当于 JDBC 中 statement 对象(或 PreparedStatement 或 CallableStatement)
默认的执行器 SimpleExcutor 批量操作 BatchExcutor
通过 openSession(ExecutorType type)控制
ExecutorType是一个枚举类型
4.DefaultSqlSession 是 SqlSession 接口的实现类
流程
1.MyBatis运行时,先通过Resources加载全局配置文件
2.通过SqlSessionFactoryBuilder构建器创建SqlSessionFactory
其内部实现了创建了SqlSessionFactory接口的实现类DefaultSqlSessionFactory
在创建DefaultSqlSessionFactory之前,需要先创建XmlConfigBuilder解析xml文件,并将解析结果存放在Configuration对象中,之后把Configuration传递给DefaultSqlSessionFactory对象
从而创建了SqlSessionFactory工厂
3.每次创建session对象时,都需要TransactionFactory 创建 Transaction 对象,同时还需要创建 SqlSession 的执行器 Excutor,最后实例化 DefaultSqlSession,传递给 SqlSession 接口
4.调用SqlSession的方法执行增删改查功能
查询方式
selectList()
selectList返回值为List<resultType属性>
SqlSession sqlSession=factory.openSession();
List<User> list=sqlSession.selectList("cn.com.mapper.UserMapper.selectAll");
for (User u:list){
System.out.println(u);
}
selectOne()
selectOne返回值为Object
<select id="selectCount" resultType="int">
select count(*) from user
</select>
int count=sqlSession.selectOne("cn.com.mapper.UserMapper.selectCount"); System.out.println(count);
selectMap()
selectMap() 返回值 Map
适用于需要在查询结果中通过某列的值取到这行数据的需求.
<select id="selectMap" resultType="cn.com.pojo.User">
select username,password from user
</select>
Map<Object,Object> map=sqlSession.selectMap("cn.com.mapper.UserMapper.selectMap","username");
System.out.println(map.get("reverie"));
在user表中有username和password两个列
所以selectMap的第二个参数为所需要映射的列名
则map中的key为第二参数指定列中的数据,value为resultType所指定的数据
parameterType 属性
在 XXXMapper.xml 中等标签的 parameterType 可以 控制参数类型
.SqlSession 的 selectList()和 selectOne()的第二个参数和 selectMap() 的第三个参数都表示方法的参数.
<select id="selectByName" resultType="cn.com.pojo.User" parameterType="string">
select * from user where username=#{param1}
</select>
User user=sqlSession.selectOne("cn.com.mapper.UserMapper.selectByName","reverie");
System.out.println(user);
parameterType 控制参数类型
1. #{}获取参数内容
使用索引,从 0 开始 #{0}表示第一个参数
也可以使用#{param1}第一个参数
如果只有一个参数(基本数据类型或 String),mybatis对#{}里面内容没有要求只要写内容即可,
<select id="selectByName" resultType="cn.com.pojo.User" parameterType="string">
select * from user where username=#{acascasc}
</select>
只有一个参数,所以#{}中的内容可以乱写
2.参数是对象
<select id="selectByName" resultType="cn.com.pojo.User" parameterType="cn.com.pojo.User">
select * from user where username=#{username}
</select>
User u=new User();
u.setUsername("reverie");
u=sqlSession.selectOne("cn.com.mapper.UserMapper.selectByName",u);
System.out.println(u);
如果参数是对象#{属性名}
如果参数是 map 写成#{key}
#{} 和 ${} 的区别
#{} 获取参数的内容支持 索引获取,param1 获取指定位置参数, 并且 SQL 使用?占位符
在日志打印中可以看出 #{}使用的是占位符
$ {} 使用的是字符串拼接方式,而不使用?占位符,默认找${内容}内容的 get/set 方法,如果写数字,就是一个数字
<select id="selectByName" resultType="cn.com.pojo.User" parameterType="cn.com.pojo.User">
select * from user where username='${username}'
</select>
可以看出未使用?占位符
使用的是字符串拼接
<select id="selectByName" resultType="cn.com.pojo.User" parameterType="cn.com.pojo.User">
select * from user where username=${username}
</select>
因为username是一个字符串类型,所以在拼接的时候要在${}前后加单引号
如果不加就报错了
typeAliases 别名
<select id="selectByName" resultType="cn.com.pojo.User" parameterType="cn.com.pojo.User">
select * from user where username=#{username}
</select>
在resultType属性和parameterType中时用的是全路径名称(包名+类名)
其实可以使用别名的方式简化别名
类别名
给某个类起别名
<?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>
<!--添加别名-->
<typeAliases>
<typeAlias type="cn.com.pojo.User" alias="u" />
</typeAliases>
<environments default="default">
<environment id="default">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOlED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/db_contracts?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="cn/com/mapper/UserMapper.xml" />
</mappers>
</configuration>
<select id="selectByName" resultType="u" parameterType="u">
select * from user where username=#{username}
</select>
定义别名后可以在resultType和parameterType中使用别名
User u=new User();
u.setUsername("reverie");
u=sqlSession.selectOne("cn.com.mapper.selectByName",u);
System.out.println(u);
包别名
.直接给某个包下所有类起别名,别名为类名,不区分大小写
<typeAliases>
<package name="cn.com.pojo"/>
</typeAliases>
<select id="selectByName" resultType="user" parameterType="user">
select * from user where username=#{username}
</select>
MyBatis的增删改
在 mybatis 中默认是关闭了JDBC 的自动提交功能
每一个 SqlSession 默认都是不自动提交事务. 所以使用session.commit()提交事务.
构造SqlSession可以使用openSession(true)设置自动提交,相当于JDBC的setAutoCommit(true);
mybatis 中<insert> <delete> <update>
标签没有 resultType 属性,返回值都是int
增加数据
<insert id="ins" parameterType="User">
insert into people values(#{username},#{password})
</insert>
User user=new User();
user.setUsername("kryie");
user.setPassword("123");
int index=sqlSession.insert("cn.com.mapper.UserMapper.ins",user);
sqlSession.commit();
if(index>0)
System.out.println("成功");
else
System.out.println("失败");
修改数据
<update id="update" parameterType="User">
update user set password=#{password} where username=#{username}
</update>
User user=new User();
user.setUsername("kryie");
user.setPassword("123456");
int index=sqlSession.update("cn.com.mapper.UserMapper.update",user);
sqlSession.commit();
if(index>0)
System.out.println("成功");
else
System.out.println("失败");
删除数据
<delete id="delete" parameterType="User">
delete from user where username=#{username}
</delete>
User user=new User();
user.setUsername("kryie");
user.setPassword("123456");
int index=sqlSession.delete("cn.com.mapper.UserMapper.delete",user);
sqlSession.commit();
if(index>0)
System.out.println("成功");
else
System.out.println("失败");
MyBatis缓存
应用程序和数据库之间的数据交互是一个好耗时的过程
类似于计算机中的缓存,在MyBatsi中是有缓存的。从而减少了对数据库的访问
在MyBatis中是默认开启缓存的
同一个SqlSession对象在调用同一个<select>
时,在第一次访问时,会将查询结果存放在缓存中,下一次再访问这个<select>
时会从缓存中拿
1.缓存
public static void main(String[] args) throws IOException {
InputStream is= Resources.getResourceAsStream("MyBatis.xml");
SqlSessionFactory factory= new SqlSessionFactoryBuilder().build(is);
//生产SqlSession
SqlSession sqlSession=factory.openSession();
sqlSession.selectList("cn.com.mapper.UserMapper.selectAll");
sqlSession.selectList("cn.com.mapper.UserMapper.selectAll");
}
可以看出只查询了一次,因为第二次是直接从缓存中拿的
2.测试范围
SqlSession sqlSession=factory.openSession();
SqlSession sqlSession2=factory.openSession();
sqlSession.selectList("cn.com.mapper.UserMapper.selectAll");
sqlSession2.selectList("cn.com.mapper.UserMapper.selectAll");
现在使用两个SqlSession去调用同一个select
可以看出执行了两次
这是因为缓存的有效范围是同一个SqlSession对象
3.缓存对象
在MyBatis中,缓存的是statement对象,
一个select对应一个statement对象
查看源码可以看出一个selct对应一个statement对象
每次执行select的流程
1.先在缓存区中找是否存在相应的statement对象 ,如果存在则返回结果
2.如果不存则去数据库获取数据
3.从数据库返回查询结果
4.把查询结果放到对应的缓存区中