一、Mybatis的基本使用
MyBatis框架
一种ORM(Object Relationship Mapping对象关系映射)框架
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录------百度百科
Hibemate: 全自动框架、封装了SQL
MyBatis : 半自动框架、需要配置SQL(可用于SQL优化)
1、MyBatis的基本使用(注意是在IDEA中)
步骤:
1)导入mybatis、mysql-connector-java依赖
2)添加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>
<!--环境配置 default指定默认环境-->
<environments default="develop">
<!--配置开发环境-->
<environment id="develop">
<!--配置事务管理器的类型:JDBC-->
<transactionManager type="JDBC"/>
<!--配置数据源,类型为连接池-->
<dataSource type="POOLED">
<!--配置驱动类型、url、账号、密码-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/bookdb?serverTimezone=CST&useSSL=false&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
</configuration>
3)添加实体类和DAO层的接口
4)配置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">
<!--配置接口的映射,namespace命名空间设置为包名+接口名-->
<mapper namespace="com.hopu.mybatis.dao.BookMapper">
<!--配置add方法的SQL语句 id是方法名 parameterType是参数类型
SQL语句中#{参数} 参数名和实体类的属性一致
-->
<insert id="add" parameterType="com.hopu.mybatis.entity.TbBook">
insert into tb_book(book_name, book_price, book_author, book_publish_date, book_image)
values(#{bookName},#{bookPrice},#{bookAuthor},#{bookPublishDate},#{bookImage})
</insert>
</mapper>
5)添加映射文件到mybatis配置中
<mapper resource="mapper/BookMapper.xml"/> </mappers>
2.MyBatis的API
SqlSessionFactoryBuilder : 会话工厂构建器
用于创建SqlSessionFactory
核心方法:SqlSessionFactory build(InputStream in)
通过配置文件的输入流创建会话工厂
SqlSessionFactory :会话工厂
openSession() 打开会话(创建新的数据库连接)
SqlSession
Connection getConnection()
select
update
insert
delete
Mapper接口 getMapper(Mapper接口类型)
commit 提交事务
close 关闭会话
面试题:为什么直接可以使用接口实现操作,不需要定义实现类?
通过动态代理生成接口的实现类,返回实现类的对象
MyBatis的查询
select标签
|id|方法名 |
|paramterType|参数类型|
| resultType |返回类型(如果实体类在属性名和表字段一样,使用resultType) |
| resultMap| 返回类型映射(如果实体类在属性名和表字段不一样,使用resultMap进行映射)|
<!--配置结果映射 id是名称,type是实体类类名-->
<resultMap id="bookMap" type="com.hopu.mybatis.entity.TbBook">
<!--配置主键,property是对象属性名,column表的列名,javatype是属性类型,jdbcType是列类型-->
<id property="bookId" column="book_id" javaType="java.lang.Long" />
<!--配置非主键列-->
<result property="bookName" column="book_name"/>
<result property="bookPrice" column="book_price"/>
<result property="bookAuthor" column="book_author"/>
<result property="bookPublishDate" column="book_publish_date"/>
<result property="bookImage" column="book_image"/>
</resultMap>
MyBatis的注解配置
@Insert、@Update、@Delete、@Select
四个注解都配置到接口的方法上
@Select注解上可以使用@ResultType或Results配置结果类型
@Results(id = "bookMap",value = {@Result(id = true,property = "bookId",column = "book_id"),
@Result(property = "bookName",column = "book_name"),
@Result(property = "bookAuthor",column = "book_author"),
@Result(property = "bookPrice",column = "book_price"),
@Result(property = "bookPublishDate",column = "book_publish_date"),
@Result(property = "bookImage",column = "book_image")})
@Select("select * from tb_book where book_id = #{bookId}")
TbBook selectById(Long bookId);
@ResultMap(value = "bookMap")
@Select("select * from tb_book")
List<TbBook> selectAll();
@Param注解用于配置方法的参数,对应SQL中#{参数名}
映射的地址使用class配置
<mapper class="com.hopu.mybatis.dao.BookMapper"/>
MyBatis的线程同步问题
SqlSessionFactory每次调用openSession后都会创建一个新的SqlSession,执行增删改查操作是会创建大量的SqlSession造成资源浪费
解决方法:
将SQLSession定义为单独的对象
出现问题:SQLSession不是线程安全的,因为SqlSession中封装的Connection不是线程安全的,在多线程同时访问时会出现问题
解决方法:上锁机制(以时间换空间)
出现问题:所有线程排队执行,效率低
解决方法:ThreadLocal线程局部变量(以空间换时间)
为每一个线程单独创建一个SqlSession绑定到线程上
上锁机制:
ThreadLocal机制:
为每个线程创建独立的对象,每个线程拥有自己的对象,不会相互影响
ThreadLocal使用方法:
ThreadLocal<对象类型> threadLocal = new ThreadLocal<>();
在当前线程中保存对象:
threadLocal.set(对象)
获得当前线程中的对象:
类型 对象 = threadLocal.get();
编写MyBatis工具类
/**
* MyBatis工具类
*/
public class MyBatisUtil {
private static SqlSessionFactory factory = null;
//保存SqlSession的线程布局变量
private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>();
static{
//初始化工厂
factory = new SqlSessionFactoryBuilder().build(
MyBatisUtil.class.getClassLoader().getResourceAsStream("mybatis.xml"));
}
/**
* 获得当前线程中的SqlSession
* @return
*/
public static SqlSession getSession(){
//读取当前线程中的SQLSession
SqlSession sqlSession = threadLocal.get();
if(sqlSession == null){
//如果为空,就创建SqlSession
sqlSession = factory.openSession();
//保存到当前线程中
threadLocal.set(sqlSession);
}
return sqlSession;
}
/**
* 关闭SqlSession
*/
public static void closeSession(){
//读取当前线程中的SQLSession
SqlSession sqlSession = threadLocal.get();
if(sqlSession != null){
//如果不为空,就关闭SqlSession
sqlSession.close();
sqlSession = null;
//线程局部变量中的SqlSession设置为null
threadLocal.set(null);
}
}
}