一、MyBatis初次使用
2.1 环境搭建步骤
MyBatis 的 API : https://mybatis.org/mybatis-3/zh/getting-started.html
1.引入依赖包
2.准备核心配置件
db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://123.57.206.19:3306/demo?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username=root
password=123456
mybatis.xml
在resources下定义MyBatis的配置文件,无固定名,但大部分人使用 resources/mybatis.xml.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><properties resource="db.properties"></properties>
<!-- <settings>-->
<!-- <setting name="logImpl" value="LOG4J"/>-->
<!-- </settings>--><typeAliases><!--给单个类起别名。 type:类型 alias:别名--><typeAlias type="com.test.pojo.Student" alias="student"></typeAlias><!--给指定包下所有类起别名。 别名=类名(不区分大小写)--><package name="com.test.pojo"/></typeAliases><!-- 配置mybaits中数据库连接环境--><environments default="mysql"><environment id="mysql"><!--配置myabtis中事务 和 JDBC 保持一致--><transactionManager type="JDBC"></transactionManager><!-- 配置连接数据库的4个元素, 底层采用的是数据库连接池的方式--><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment></environments><!--扫描mapper文件--><mappers><mapper resource="mapper/student.xml"></mapper></mappers>
</configuration>
3.书写mapper文件
resources/**.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace: 代表xml的名称,类似java包名-->
<mapper namespace="com.beiyou.dao.StudentDao"><!-- 查询所有学生 List<Student> selectAll()--><!--select: 代表进行查询操作。id: 之前的方法名称,具有唯一性。resultType: 返回值类型。如果返回的是对象,直接书写对象类型的的完整名。如果是集合,书写的是集合的泛型parameterType: 参数类型,可以省略。--><select id="selectAll" resultType="com.beiyou.entity.Student" >select * from student</select></mapper>
非必需
<build><resources><resource><directory>src/main/java</directory><!--所在的目录--><includes><!--.xml 文件都会扫描到,包括子目录--><include>**/*.xml</include></includes><filtering>false</filtering></resource><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource></resources>
</build>
4.构建SqlSessionFactory。
从xml中创建SqlSessionFactory.
// 1. 解析扫码 mybatis.xml 文件
InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
// 2. 获取sqlsession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 3. 获得 sqlsession 对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 4. 执行sql语句
List<Student> students = sqlSession.selectList("com.beiyou.dao.StudentDao.selectAll");
// 打印结果
System.out.println(students);
是否弥补了JDBC的不足?
二、MyBatis 配置细节
2.1 log4j的使用
-
加入依赖
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>
-
配置文件 log4j.properties
#定义全局日志级别调试阶段推荐debug
log4j.rootLogger = error,stdout
#包级别日志
log4j.logger.test.a = debug### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.SimpleLayout### 输出日志到文件=/logs/log.log ###
log4j.appender.logfile = org.apache.log4j.DailyRollingFileAppender
log4j.appender.logfile.File = /logs/log.log
log4j.appender.logfile.layout = org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
2.2 事务配置
transactionManager.type
JDBC : 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
MANAGED : 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期。
2.3 连接池配置
dataSource.type
UNPOOLED : 这个数据源的实现会每次请求时打开和关闭连接.
POOLED : 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。
JNDI : 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的数据源引用。
2.4 映射文件的加载方式
1.resource: 使用相对于类路径的资源引用。
<mapper resource="AuthorMapper.xml"/>
2.url: 使用完全限定资源定位符(URL)
<mapper url="file:///D:/207/mybatis/src/main/resources/mapper/BlogMapper.xml"/>
3.class : 使用映射器接口实现类的完全限定类名
<mapper class="org.mybatis.builder.BlogMapper"/>
4.name : 将包内的映射器接口实现全部注册为映射器
<mappers><package name="com.beuyou.dao"/>
</mappers>
2.5 实体类别名处理
<typeAliases><!--给单个类起别名。 type:类型 alias:别名--><typeAlias type="com.beiyou.entity.Student" alias="student"></typeAlias><!--给指定包下所有类起别名。 别名=类名(不区分大小写)--><package name="com.beuyou.entity"/>
</typeAliases>
常见的 Java 类型内建的类型别名。它们都是不区分大小写的
别名 | 映射的类型 |
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
2.6 外部属性配置文件存储数据库信息
-
配置db.properties数据库信息
driver=com.mysql.cj.jdbc.Driver
url=mysql://rm-bp169j3q9n43kxauzco.mysql.rds.aliyuncs.com:3306?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username=root123
password=Root_123
<properties resource="db.properties"></properties><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource>
三、Mapper文件配置
3.1 常用属性
3.2 SQL 定义标签
1. select
用于数据查询操作,例:
<select id="selectUserInfo" parameterType="int" resultType="map">select * from user_info where id=#{keyId}
</select>
2. insert
用于数据保存操作,例:
<insert id="insertUserInfo" parameterType="map" useGeneratedKeys="true" keyProperty="keyId">insert into user_info (userName,userSex)values(#{userName},#{userSex})
</insert>
PS:keyProperty属性可返回此条插入数据的主键值
3. update
用于数据更新操作,例:
<update id="updateUserInfo" parameterType="map">update user_infoset userName=#{userName}where id=#{keyId}
</update>
4. delete
用于数据删除操作,例:
<delete id="selectUserInfo" parameterType="int">delete from user_info where id=#{keyId}
</delete>
5. resultMap
SQL返回与实体类映射关系信息,例
<resultMap id="userInfoMap" type="User"><result property="user_name" column="userName"/><result property="user_sex" column="userSex"/>
</resultMap>
<select id="selectUserInfo" parameterType="int" resultType="userInfoMap">selectuserName,userSexfrom user_info where id=#{keyId}
</select>
将数据表字段userName、userSex映射到实体类User的user_name、user_sex
6. sql
用于定义可重用的 SQL 代码片段,以便在多个SQL语句中使用。 参数可以静态地(在加载的时候)确定下来,并且可以在不同的 include 元素中定义不同的参数值。例:
<!-- 定义 -->
<sql id="userColumns"> ${alias}.userName,${alias}.userSex</sql>
<!-- 运用 -->
<select id="selectUserInfo" resultType="map">select<include refid="userColumns"><property name="alias" value="t1"/></include>,<include refid="userColumns"><property name="alias" value="t2"/></include>from user_info t1left join user_info_copy t2
</select>
3.3、SQL动态标签
1. if
单个条件判断,用以实现条件筛选,例:
<select id="selectUserInfo" parameterType="map" resultType="map">select * from user_info where 1=1<if test="userSex !=null and userSex !='' ">and userSex=#{userSex}</if><if test="userName !=null and userName !='' ">and userName like CONCAT('%',#{userName},'%')</if>
</select>
2. foreach
用于更新或保存数据时的批量操作,例:
<!-- userList为List<HashMap<String,Object>>类型数据 -->
insert into user_info(
userName,
userSex
)values
<foreach item="item" index="index" collection="userList" separator="," >
(
#{item.userName},
#{item.userSex}
)
</foreach>
<!-- userList为List<String>类型数据 -->
insert into user_info(
userName
)values
<foreach item="item" index="index" collection="userList" separator="," >
(
#{userName}
)
</foreach>
update user_info
set userAge=#{userAge}
where id in
<foreach collection="keyIds" index="index" item="item" separator="," open="(" close=")">
#{item}
</foreach>
3. choose/when/otherwise
用以实现条件的多种判断,类似与if else,例:
<select id="selectUserInfo" parameterType="map" resultType="map">select * from user_info where 1=1<choose><when test="userFlag!=null and userFlag!='' and userFlag=='Y'">and id<=100</when><when test="userFlag!=null and userFlag!='' and userFlag=='N'">and id <=200</when><otherwise>and id<=300</otherwise></choose>
</select>
4. where
只会在子元素返回任何内容的情况下才插入 “WHERE” 子句,并且可以自动处理判断条件语句返回的第一个and或or,例:
不使用where标签时,若userSex为空,语法错误会报错:
<select id="selectUserInfo" parameterType="map" resultType="map">select * from user_info where<if test="userSex !=null and userSex !='' ">userSex=#{userSex}</if><if test="userName !=null and userName !='' ">and userName like CONCAT('%',#{userName},'%')</if>
</select>
修改为:
<select id="selectUserInfo" parameterType="map" resultType="map">select * from user_info<where><if test="userSex !=null and userSex !='' ">userSex=#{userSex}</if><if test="userName !=null and userName !='' ">and userName like CONCAT('%',#{userName},'%')</if></where>
</select>
自动转换为:select * from user_info where userName like ……
5. set
可以动态更新需要更新的列,忽略其它不更新的列,例:
<update id="updateUserInfo" parameterType="map">update user_info<set><if test="userName!= null and userName!=''">userName=#{userName},</if>userSex=#{userSex}</set>where id=#{keyId}
</update>
四、基于MyBatis的CURD操作
使用单元测试验证
<dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.6.0</version><scope>test</scope></dependency>
4.1 MyBatis查询的三种方式
-
返回单个对象 selectOne
-
返回对象List集合 selectList
-
返回对象Map集合 selectMap
<select id="selectOne" resultType="student">select * from student where id=1
</select>
<select id="selectAll" resultType="student" >select * from student
</select>
<select id="selectMap" resultType="map">select * from student
</select>
4.2 MyBatis参数传递的三种方式
4.2.1 三种传参
-
传递的是基本类型+String ,使用 param1
-
传递类型是对象,接受使用对象的 属性名
-
传递的是map集合,接受时候使用map中的 key
<!-- 方法 Student selectOne(int id)-->
<!--param1:-->
<select id="selectOne" resultType="student" parameterType="int">select * from student where id = #{id}
</select>
<!-- 方法 Student selectOne(StudentQuery query)-->
<!--#{} 里面放的是对象属性-->
<select id="selectOne2" resultType="student">select * from student where id = #{id} and name = #{name}
</select>
<!-- 方法 Student selectOne(Map map)-->
<!--#{} 里面放的是map的key-->
<select id="selectOne3" resultType="student">select * from student where id = #{a} and name = #{b}
</select>
// 【A】. 传递基本类型Student student = sqlSession.selectOne("test.c.selectOne", 2);// 打印System.out.println(student);// 【B】. 传递对象StudentQuery query = new StudentQuery();query.setId(2);query.setName("周星星");Student student = sqlSession.selectOne("test.c.selectOne2", query);//打印System.out.println(student);//【C】. 传递Map集合//id,name 一块封装到map集合Map<String,Object> map = new HashMap<>();map.put("a",2);map.put("b","周星星");Student student = sqlSession.selectOne("test.c.selectOne3", map);//打印System.out.println(student);
4.2.2 #和$区别:面试题
#:底层相当于占位符?
$:底层相当于字符串拼接
-
两者相比,占位符的方式更加方便,可以有效的防止SQL注入。
-
预编译
4.2.3 模糊查询
<!-- 模糊查询 -->
<select id="selectOne4" resultType="student">Student student = sqlSession.selectOne("test.c.selectOne4", "%敏%");select * from student where name like #{param1}Student student = sqlSession.selectOne("test.c.selectOne4", "敏");select * from student where name like concat('%',#{param1},'%')
</select>
4.2.4 Model对象字段名称与数据库不一致,使用resultMap指定
<select id="selectlike2" resultMap="usermap" >select * from user where email like concat('%',#{param1},'%')</select><resultMap id="usermap" type="User"><!--主键映射 使用id标签propetry java中的类型名称column 数据库中的字段名--><id property="pwd" column="password"/></resultMap>
XML
4.2.5 include标签
1、首先定义一个sql标签,一定要定义唯一id。 <sql id="columns">id, title ,brief</sql>
2、然后通过id引用 <select id="selectOne" resultMap="productResultMap1" >select<include refid="columns"/>from product where id = 8</select>
XML
4.3 MyBatis完整DML全部操作
DML与DDL的含义:
1、DML(Data Manipulation Language)数据操作语言-数据库的基本操作,SQL中处理数据等操作统称为数据操纵语言,简而言之就是实现了基本的“增删改查”操作。包括的关键字有:select、update、delete、insert、merge
2、DDL(Data Definition Language)数据定义语言-用于定义和管理 SQL 数据库中的所有对象的语言,对数据库中的某些对象(例如,database,table)进行管理。包括的关键字有:
create、alter、drop、truncate、comment、grant、revoke
4.3.1 CUD
【1】新增
<!-- 方法 int insert(Student student)-->
<insert id="insert">insert into student (name,age) values (#{name},#{age})
</insert>
Student student = new Student();
student.setName("邓超");
student.setAge(38);
int rowNum = sqlSession.insert("com.beiyou.dao.StudentMapper.insert", student);
//MyBatis 默认不自动提交事务,所以 增删改功能 需要我们手动提交事务
sqlSession.commit();
【2】修改
<!-- 传统方法 int update(Student student)-->
<update id="update">update student set name = #{name},age = #{age} where id = #{id}
</update>
Student student = new Student();
student.setName("邓超111");
student.setAge(380);
student.setId(6);
int rowNum = sqlSession.update("com.beiyou.dao.StudentMapper.update", student);
//MyBatis 默认不自动提交事务,所以 增删改功能 需要我们手动提交事务
sqlSession.commit();
【3】删除
<!-- 传统方法 int delete(int id)-->
<delete id="delete">delete from student where id = #{param1}
</delete>
int rowNum = sqlSession.delete("test.d.delete", 6);
//MyBatis 默认不自动提交事务,所以 增删改功能 需要我们手动提交事务
sqlSession.commit();
4.3.2 设置SqlSession提交
MyBatis 默认不自动提交事务,所以 增删改功能 需要我们手动提交事
【1】SqlSession sqlSession = factory.openSession(true);
【2】sqlSession.commit();
4.4 扩展
4.4.1 接口编程
package com.beiyou.dao;public interface UserDao {List<User> selectAll();
}
<mapper namespace="com.beiyou.dao.UserDao"><select id="selectAll" resultType="user" >select * from 202_user</select></mapper>
UserDao mapper = sqlSession.getMapper(UserDao.class);mapper.selectAll();
4.4.2通过表达式,实现多场景多条件组合查询
<select id="select" resultMap="productResultMap1">select id, categoryId,title ,brief from 202_product<where><if test="id != null">and id = #{id}</if><if test="ids != null">and id in<foreach collection="ids" item="item" open="(" close=")" separator=",">#{item}</foreach></if><if test="categoryId != null">and categoryId= #{categoryId}</if><if test="categoryIds != null">and categoryId in<foreach collection="categoryIds" item="item" open="(" close=")" separator=",">#{item}</foreach></if><if test="name != null">and title like concat('%',#{name},'%')</if></where></select>
@Testpublic void selectQuery() throws IOException {ProductDao productDao = sqlSession.getMapper(ProductDao.class);ProductQuery query = new ProductQuery();//query.setId(40);//query.setCategoryId(1);//query.setName("梨38");//query.setIds(new Integer[]{38,42,50,51,52});query.setCategoryIds(new Integer[]{3});List<Product> products = productDao.select(query);System.out.println(products);}
4.4.3 注解
<mapper class="com.beiyou.dao.UserDao"/>
public interface UserDao {@Select("select * from 202_user limit 1")User select(); //insert into order_item (productId,productName,productImg,price,qty,orderId) values (1,2,3),(2,3,4).....@Insert("<script> " +"insert into " +" order_item (productId,productName,productImg,price,qty,orderId) " +"values " +"<foreach collection='items' item='item' separator=','> "+"(#{item.productId},#{item.productName},#{item.productImg},#{item.price},#{item.qty},#{item.orderId})"+"</foreach> </script>" )int insertAll(List<OrderItemEntity> items);@Select("<script> " +"select * from order_item where 1 = 1 " +"<if test='id != null'>" +" and id = #{id} "+"</if> "+"<if test='orderId != null'>" +" and orderId = #{orderId} "+"</if> "+"<if test='orderIds != null'>" +" and orderId in "+"<foreach collection='orderIds' open='(' close=')' item='item' separator=','> "+"#{item}"+"</foreach> "+"</if> "+"</script>" )@Results(id="studentMap",value={ @Result(column=“id”, property=“id”, jdbcType=JdbcType.INTEGER, id=true), @Result(column=“name”, property=“name”, jdbcType=JdbcType.VARCHAR), @Result(column=“class_id”, property=“classId”, jdbcType=JdbcType.INTEGER)})List<OrderItemEntity> select(OrderItemQueryDto queryDto);}
4.4.4 SelecKey标签使用
Mybatis之useGeneratedKeys和selectKey的基本用法与区别_mybatis selectkey usegeneratedkeys_poppyCL的博客-CSDN博客
一、useGeneratedKeys数据库本身具备主键自动增长的功能,才能使用useGeneratedKeysoracle不支持true<insert id="insert" useGeneratedKeys="true" keyProperty="idColName"> insert into tableName (colName) values (#{colVal,jdbc..._mybatis selectkey usegeneratedkeys
https://blog.csdn.net/poppyCL/article/details/103347385
<insert id="insert" parameterType="UserEntity">insert user (email,password) values (#{email},#{pwd})<selectKey keyProperty="id" resultType="integer" keyColumn="newId" order="AFTER">SELECT LAST_INSERT_ID() as newId</selectKey></insert><selectKey resultType="integer" keyColumn="newId" keyProperty="id" order="BEFORE">SELECT (max(id)+1) as newId from 205_category
</selectKey>
注解版
@SelectKey(statement="SELECT last_insert_id", keyProperty="id", before=false, resultType=Long.class)
五 MyBatis 高级关系查询
-
一个会员只属于一个详情 ==> 会员对详情表是一对一关系
-
不管是一对一还是多对多,都要使用<resultMap> ,属性有id 和type
-
一对一中,<resultMap>内要用<association>来映射复杂对象,属性有 :
-
(property和javaType) ==> 嵌套结果
-
(property, column, select) ==> 嵌套查询
-
一对多中,<resultMap>内要用<collection>来映射复杂对象,属性有property和ofType
-
注意防范<resultMap>和<association>或<collection>中字段名冲突的问题!
5.1 一对一
<resultMap> <association>
<association> 元素,通常可以配置一下属性
- propery:指定映射到实体类对象属性,与表字段一一对应
- column:指定表中对应的字段
- javaType:指定映射到实体对象属性的类型
- select:指定引入嵌套查询的子SQL语句,该属性用于关联映射中的嵌套查询
- fetchType:指定在关联查询时是否启用延迟加载。FetchType属性有lazy和eager(实时)两个属性值,默认值为lazy
默认为lazy(默认关联映射延迟加载)
create table 202_user( id int unsigned auto_increment, tel varchar(50) not null, password varchar(32) not null, primary key(id));
CREATE TABLE `202_userinfo` (`id` int NOT NULL AUTO_INCREMENT COMMENT '唯一标识',`name` varchar(100) NOT NULL COMMENT '姓名',`sex` varchar(100) DEFAULT NULL COMMENT '性别',PRIMARY KEY (`id`)
)
实体对象
@Data public class User { private Integer id; private String tel; private String password; private UserInfo userinfo;}public class UserInfo { private Integer id; private String name; private String sex; private Integer age;
}
UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.beiyou.dao.UserDao2"><resultMap id="usermap" type="com.beiyou.model.User"><id property="id" column="id"/><result property="tel" column="tel"/><result column="password" property="password"/><association property="userInfo" javaType="com.beiyou.model.UserInfo"><id property="id" column="id"/><result property="name" column="name"/><result property="sex" column="sex"/></association></resultMap><select id="one2one" resultMap="usermap" >select *from `202_user` uleft join `202_userinfo` uion u.id = ui.userId</select><resultMap id="userMap" type="com.beiyou.model.User"><id column="id" property="id"/><result column="tel" property="tel"/><result column="password" property="password"/><association property="userInfo" column="Id" fetchType="lazy" javaType="com.beiyou.model.UserInfo"select="selectUserinfo"><id property="id" column="id"/> bug 必须书写<result property="name" column="name"/><result property="sex" column="sex"/></association></resultMap><select id="lazyone2one" resultMap="usermap2">select * from 202_user</select><select id="selectName" resultType="com.beiyou.model.UserInfo">select * from 202_userinfo where userId = #{id}</select>
</mapper>
UserDao.java
public interface UserDao {User one2one(String name);User lazyone2one(String name);
}
5.2 一对多
<resultMap> <collection>
CREATE TABLE `202_address` (`id` int NOT NULL AUTO_INCREMENT COMMENT '唯一id',`userId` int NOT NULL COMMENT '用户编号',`province` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '省',`city` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '市',`address` varchar(100) DEFAULT NULL COMMENT '详细地址',PRIMARY KEY (`id`)
)
<resultMap id="userMap" type="com.beiyou.model.User"><id column="id" property="id"/><result column="tel" property="tel"/><result column="password" property="password"/><association property="userInfo" column="Id" fetchType="lazy" javaType="com.beiyou.model.UserInfo"select="selectUserinfo"><id property="id" column="id"/><result property="name" column="name"/><result property="sex" column="sex"/></association><collection property="addresses" column="id" fetchType="lazy" javaType="java.util.ArrayList"ofType="com.beiyou.model.Address" select="selectAddress" ><id property="id" column="id"/><result property="province" column="province"/><result property="city" column="city"/><result property="county" column="county"/><result property="address" column="address"/></collection>
</resultMap><select id="selectAddr" resultType="com.beiyou.model.Address">select * from 202_address where userId = #{userId}</select>
使用Mapper注解,实现一对一和一对多关系查询
@Results(id="userMap", value = {@Result(column = "id", property = "id", id = true),@Result(column = "tel", property = "tel"),@Result(column = "password", property = "password"),@Result(property = "userInfo", column = "id",one = @One(select = "selectUserinfo",fetchType = FetchType.LAZY)), 可以不用写具体映射,但是用xml的时候,必须写@Result(column = "id", property = "addresses" ,many = @Many(select = "selectAddress",fetchType = FetchType.LAZY))})}@Select("select * from 202_user u where u.id = #{id}")List<User> layeOne2One(int id);@Select("select * from 202_address where userId = #{id}")List<Address> selectAddress(Integer id);
测试代码
@Testpublic void test(){UserMapper2 dao = sqlSession.getMapper(UserMapper2.class);List<User> users = dao.queryUserAll();}
Java
六 MyBatis缓存机制
mybatis.xml
<settings><setting name="cacheEnabled" value="true"/> //开启全局的二级缓存</settings>
//清空缓存数据@Options(flushCache = Options.FlushCachePolicy.TRUE)@Select(" select * from 202_user where id= 46")User one();
6.1 一级缓存
一级缓存作用域是sqlsession级别的,同一个sqlsession中执行相同的sql查询(相同的sql和参数),第一次会去查询数据库并写到缓存中,第二次从一级缓存中取。
一级缓存是基于 PerpetualCache 的 HashMap 本地缓存,默认打开一级缓存。
6.1.1何时清空一级缓存
如果中间sqlSession去执行commit操作(执行插入、更新、删除),则会清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
一级缓存时执行commit,close,增删改等操作,就会清空当前的一级缓存;当对SqlSession执行更新操作(update、delete、insert)后并执行commit时,不仅清空其自身的一级缓存(执行更新操作的效果),也清空二级缓存(执行commit()的效果)。
6.1.2一级缓存无过期时间,只有生命周期
MyBatis在开启一个数据库会话时,会创建一个新的SqlSession对象,SqlSession对象中会有一个Executor对象,Executor对象中持有一个PerpetualCache对象。当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。
6.2 二级缓存
它指的是Mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。
同一个工厂生产的sqlsession,批次号相同.
二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。
6.2.1 二级缓存何时存入
在关闭sqlsession后(close或commit),才会把该sqlsession一级缓存中的数据添加到namespace的二级缓存中。
开启了二级缓存后,还需要将要缓存的pojo实现Serializable接口,为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一定只存在内存中,有可能存在硬盘中
6.2.2二级缓存有过期时间
每当存取数据的时候,都有检测一下cache的生命时间,默认是1小时,如果这个cache存活了一个小时,那么将整个清空一下.
6.2.3 执行流程
当 Mybatis 调用 Dao 层查询数据库时,先查询二级缓存,二级缓存中无对应数据,再去查询一级缓存,一级缓存中也没有,最后去数据库查找。
SqlSessionFactory级别缓存,会话工厂级别SqlSession s1 = sf.openSession();SqlSession s2 = sf.openSession();SqlSession s3 = sf.openSession();System.out.println(s1);System.out.println(s2);System.out.println(s3);开发者必须自己配置二级缓存二级缓存是人工开启的,需要在XxxxMapper.xml 文件中加入如下开启方法一<cache eviction="FIFO" flushInterval="60000" size="5120" readOnly="true" /><select id="queryAll" resultType="book" useCache="false"> 默认使用缓存,填写false此操作不让缓存select * from book</select>方法二@CacheNamespace(eviction = FifoCache.class, flushInterval = 60000, size = 1024, readWrite = true)public interface BookMapper {@Select("select * from book") @Options(useCache = true)public List<Book> queryAll();@Select("select * from book where id = #{id}")public Book queryById(int id);} 注意:使用缓存时,最好给实体类序列化。
Java
Student.java
@Data
public class Student implements Serializable {private int id;private String name;private int age;private double money;private String info;
}
Plain Text
StudentMapper.java
@CacheNamespace
public interface StudentMapper {@Select("select * from t_student")@Options(useCache = true) //开启或关闭二级缓存public List<Student> page();@Select("select * from t_student where id = #{id}")@Options(useCache = true)public Student queryById(int id);
}
Java
@Test
public void t5() {var session = sf.openSession();var sm = session.getMapper(StudentMapper.class);System.out.println(sm.page());System.out.println(sm.page());System.out.println(sm.page());System.out.println(sm.page());System.out.println("---------------------------");System.out.println(sm.queryById(5));session.commit();//将当前会话的查询,保存到二级缓存中,System.out.println(sm.queryById(5));System.out.println(sm.queryById(5));System.out.println(sm.queryById(5));System.out.println("----------------------");var s2 = sf.openSession();var sm2 = s2.getMapper(StudentMapper.class);System.out.println(sm2.queryById(5));
}
Plain Text
六 常见问题
1.MySQL连接数据库时,添加语句:“allowMultiQueries=true”的作用:
-
可以在sql语句后携带分号,实现多语句执行。
-
可以执行批处理,同时发出多个SQL语句。