目录
配置文件
mybatis-config 核心配置文件
一般放到resources中 模板代码及配置说明:
<?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>
<!-- mybatis的标签是有顺序的 顺序为: -->
<!-- properties?,settings?,typeAliases?,typeHandlers?,
objectFactory?,objectWrapperFactory?,reflectorFactory?,
plugins?,environments?,databaseIdProvider?,mappers? -->
<!-- 一些变量为了方便改动 放入 "文件名.properties"中 使用时 导入 用${变量名}-->
<properties resource="jdbc.properties"></properties>
<settings>
<!-- 开启驼峰转换
解决数据库_类型字段转为驼峰 如 user_name 与实体类userName 映射-->
<setting name="mapUnderscoreToCamelCase" value="true" />
<!--开启延时加载 按需加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="true"/>
</settings>
<typeAliases>
<!--指定别名的三种方式 可不写 使用别名避免在***Mapper.xml中使用类的全路径-->
<!-- 1 挨个指定别名-->
<!-- <typeAlias type="com.yan.pojo.User" alias="User"></typeAlias>-->
<!-- 2 类的默认简写名 ,默认为类名-->
<!-- <typeAlias type="com.yan.pojo.User" ></typeAlias>-->
<!-- 3 整个包的默认类名为别名 -->
<package name="com.yan.pojo"/>
</typeAliases>
<!-- 选择数据库开发环境 在default中 选择当前使用的环境 -->
<environments default="development">
<environment id="development">
<!-- 事务的管理方式:JDBC|MANGED 分别为 :执行sql使用JDBC原生的事务管理 事务提交、回滚需手动处理|被管理 如spring-->
<transactionManager type="JDBC"/>
<!-- 数据源类型 POOLED|UNPOOLED|JNDI 分别表示 :POOLED:表示使用数据库连接池缓存数据库连接
UNPOOLED:表示不使用数据库连接池
JNDI:表示使用上下文中的数据源-->
<dataSource type="POOLED">
<!-- 在sql5中 驱动类为com.mysql.jdbc.Driver sql8驱动类为 com.mysql.cj.jdbc..Driver
同时注意 pom中 mysql-connector-java 与自己sql安装版本是否适配-->
<property name="driver" value="${jdbc.driver}"/>
<!-- 在sql8中 url要带上时区 如 jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC-->
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
<!-- 另一个环境-->
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments> <!--引入映射文件-->
<!-- 将各个接口Xxx 对应的XxxMybatis.xml文件引入核心配置文间中 有两种方式-->
<mappers>
<!-- 1、 挨个加载配置文件 -->
<!-- <mapper resource="mappers/UserMapper.xml"/>-->
<!-- 2、以包为单位引入映射文件 要求:
1、mapper接口所在的包要和映射文件所在的包一致
2、mapper接口要和映射文件的名字一致 -->
<package name="com.yan.mapper"/>
</mappers>
</configuration>
接口Xxx对应的XxxMapper.xml模板
<?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">
<!-- 说明:
1、查询的标签select必须设置属性resultType或resultMap,用于设置实体类和数据库表的映射关系
resultType:自动映射,用于属性名和表中字段名一致的情况
一般指定别名在mybatis-config.xml 的<typeAliases>中 一般java类型都会有别名 如: java.lang.Integer->int|integer
java.lang.String ->string Map->map List->list int->_int|_integer
resultMap:自定义映射,用于一对多或多对一或字段名和属性名不一致的情况
-->
<!--一个接口对应一个配置文件 -->
<!-- User getUserById(@Param("id")Integer id);-->
<mapper namespace="com.yan.mapper.UserMapper">
<!-- 一个id对应一个一个接口中的方法 -->
<!-- User getUserById(@Param("id")Integer id);-->
<select id="getUserById" resultType="User">
select *
from t_user
where id=${id};
</select>
<!-- List<Student> getAllStudent();-->
<!--多对一查询 属性的对象的属性对应数据库中查询的字段 -->
<!-- 级联查询-->
<resultMap id="getUserMap" type="Student">
<id property="sid" column="sid"></id>
<result property="sname" column="sname"></result>
<result property="myClass.cid" column="cid"></result>
<result property="myClass.className" column="class_name"></result>
</resultMap>
<select id="getAllStudent" resultMap="getUserMap">
select student.* ,class.*
from t_student student
left join t_class class
on student.cid=class.cid
</select>
</mapper>
mybatis的工厂类
public class GetSqlSession {
static public SqlSession getSqlSession() throws IOException {
// 读取配置文件
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
// SqlSessionFactoryBuilder 读取配置文件创造 sqlSessionFactory
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
// 工厂创造一个个具体的sqlSession 返回
// 扩号内 true:事务自动提交 false:手动提交 最后执行 commit()
return sqlSessionFactory.openSession(true);
}
}
mybatis的使用
@Test
public void getUserById() throws IOException {
// 获取 SqlSession 传入接口类 通过框架找到 接口对应的mybatis.xml 接口不能调用方法 代理为一个类
SqlSession sqlSession = GetSqlSession.getSqlSession();
// 本质是找到接口对应的方法
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 调用方法 框架 读取xml中的sql语句
User userById = mapper.getUserById(9);
// 等同于
// UserMapper userById = (UserMapper)GetSqlSession.getSqlSession().selectOne("com.yan.mapper.UserMapper.getUserById",9);
// 未开启自动事务的情况下
// sqlSession.commit();
System.out.println(userById);
}
#{} 与${}
-
mybatis的本质对JDBC的封装 要将先xml中的语句转为普通的JDBC能够识别的sql语句再去执行
#{} 转为的占位符 ?默认会给值加
''
jdbc的prepareStatement 一般情况使用#{}
${} 转为字符串拼接的方式 默认不会给值加''
jdbc的statement
二者可在一个sql混用
1. #{}:
<!-- User getUserById(@Param("id")Integer id);-->
<select id="getUserById" resultType="User">
select *
from t_user
where id=#{id};
</select>
**要转为**
![在这里插入图片描述](https://img-blog.csdnimg.cn/376ff6e576be4d5a8c98b8f5a4143a25.png)
等同于
Connection con = getCon();
String sql="select *from t_user where id=?";
PreparedStatement prepareStatement = con.prepareStatement(sql);
prepareStatement.setString(1,9);
2. ${}
```xml
<select id="getUserById" resultType="User">
select *
from t_user
where id=${id};
</select>
```
**转化为**
等同于
Connection con = getCon();
Statement statement = con.createStatement();
String sql="select *from t_user where id="+id;
ResultSet resultSet = statement.executeQuery(sql);
xml中sql语句获取参数值5种情况
1. 单个参数
${}和#{}以任意的名称获取参数的值**
例:
<!-- User getUserById(Integer id);-->
<select id="getUserById" resultType="User">
select *
from t_user
where id=${aaaaaa};
${}或#{}的参数为任意 若是变量是字符串 记得${}加上''
</select>
2. 多个参数
MyBatis会自动将这些参数放在一个map集合中,以arg0(注意0开始),arg1…为键,以参数为值;以param1,param2…(注意1开始)为键,以参数为值;因此只需要通过${}和#{}访问map集合的键就可以获取相
对应的
例:
<!-- User getUserByIdAndName(Integer id,String username);-->
<select id="getUserByIdAndName" resultType="User">
select *
from t_user
where id=#{arg0}
and username=#{arg1};
</select>
变量arg 不能拼错 顺序固定 (第一个参数为0,第二个为1...)
或
<!-- User getUserByIdAndName(Integer id,String username);-->
<select id="getUserByIdAndName" resultType="User">
select *
from t_user
where id=#{param1}
and username=#{param2};
</select>
变量param 不能拼错 顺序固定 (第一个参数为1,第二个为2...)
3. 参数为map类型
sql语句中 #{}或${}的变量为map的key(不能再用arg0…或param1…)
例:
<!-- User getUserByIdAndNameMap(Map<String, Object>map);-->
<select id="getUserByIdAndNameMap" resultType="user">
select *
from t_user
where id=#{id}
and username=#{username};
</select>
@Test
public void getUserByIdAndName() throws IOException {
UserMapper mapper = GetSqlSession.getSqlSession().getMapper(UserMapper.class);
HashMap<String, Object> map = new HashMap<>();
map.put("id",9);
map.put("username","wyy");
System.out.println(mapper.getUserByIdAndNameMap(map));
}
4. 参数为实体类对象
${}和#{} 中为对象中属性名
mybatis 会通过实体类get方法查询他们对应的值
所以 用实体类做变量要有 getter ;用实体类接收查询结果要有 setter
例:
<!-- int InsertUser(User user);-->
<insert id="InsertUser">
insert into t_user values (null ,#{username},#{email});
</insert>
@Test
public void getUserByIdAndName() throws IOException {
UserMapper mapper = GetSqlSession.getSqlSession().getMapper(UserMapper.class);
User user = new User();
user.setUsername("admin000");
user.setEmail("qq");
System.out.println(mapper.InsertUser(user));
}
5. 使用@Param()
@Param注解标识mapper接口中的方法参数
此时,会将这些参数放在map集合中,以@Param()注解中的value属性值
为#{}或${}中的值(param1, param2…也适用 但arg0,arg1…不适用)
例:
<!-- User getUserByIdAndName(@Param("id") Integer id,@Param("name") String username);-->
<select id="getUserByIdAndName" resultType="User">
select *
from t_user
where id=#{id}
and username=#{name};
</select>
查询多条map集合的数据的两种方式
查询没有映射实体类的数据就要用map 一次查询多条没有实体类映射的数据就要一次返回多条map
例:
<!-- List<Map<String,Object>>getUserMap();-->
<select id="getUserMap" resultType="map">
select * from t_user
</select>
结果样式:
[{id=9, email=we, username=wyy}, {id=10, email=qq, username=admin000}]
- 使用@MapKey(“返回大map包裹小map要使用的key”)
最终要以一个map的方式返回数据,此时需要通过@MapKey注解设置map集合的键,值是每条数据所对应的 map集合
例:
接口:
@MapKey("id") 使用t_user的key作为key
Map<String,Object> getUserMap();
xml:
<select id="getUserMap" resultType="map">
select * from t_user
</select>
结果样式:
{9={id=9, email=we, username=wyy}, 10={id=10, email=qq, username=admin000}}
模糊查询的三种方式
1. 使用 ‘%${}%’
利用${}的拼接进去
<!-- User getUserByMoHU(@Param("username")String username);-->
<select id="getUserByMoHU" resultType="User">
select *
from t_user
where username
like '%${username}%'
</select>
2. 使用concat(‘%’,#{username},‘%’)
<!-- User getUserByMoHU(@Param("username")String username);-->
<select id="getUserByMoHU" resultType="User">
select *
from t_user
where username
like concat('%',#{username},'%')
</select>
3. 使用"%“#{}”%"
<!-- User getUserByMoHU(@Param("username")String username);-->
<select id="getUserByMoHU" resultType="User">
select *
from t_user
where username
like "%"#{username}"%"
</select>
in 型操作使用${}
例:删除
<!-- int delMOre(@Param("ids") String ids);-->
<delete id="delMOre">
delete
from t_user
where id in (${ids});
</delete>
例:查询:
<!-- int delMOre(@Param("ids") String ids);-->
<select id="getAllUser" resultType="User">
select *
from t_user
where username
in (${names})
</select>
动态设置表名 要使用${}
<!-- List<User> getUser(@Param("userTable") String userTable);-->
<select id="getUser" resultType="User">
select *
from ${userTable};
</select>
获取自增主键
在插入数据的同时 能查询到数据库中为其分配的自增id值
例:
<!-- int InsertUser(User user);-->
<!-- keyProperty :获取到的id保存到对象的那个属性 useGeneratedKeys: 开启获取主键 -->
<insert id="InsertUser" useGeneratedKeys="true" keyProperty="id">
insert into t_user values (null ,#{username},#{email});
</insert>
解决实体类字段与数据库字段不同的两种方法
1. 在sql语句中通过 as 起别名
例:
<!-- List<User> getUser();-->
<select id="getUser" resultType="User">
select uid as id,name as username
from user
</select>
2. 通过resultMap
<!-- List<User> getUser();-->
<!-- id 给下方resultMap绑定 type:进行映射的实体类-->
<resultMap id="userMap" type="User">
<!-- id 属性使用id标签-->
<id column="uid" property="id"></id>
<!-- 其余属性使用result标签-->
<result column="name" property="username"></result>
</resultMap>
<select id="getUser" resultMap="userMap">
select * from user
</select>
多对一 (多表一对一也适用)3种方式
如 学生表 班级表
多个学生对应一个班级 在学生实体类中 班级为对象
student 表
private Integer sid;
private String sname;
private Integer cid;
// 班级类对象
private MyClass myClass;
一个班级对应多个学生 在班级实体类中 学生为list集合对象
class 表
private Integer cid;
private String className;
//对应多个学生属性
private List<Student> students;
查询一个学生的详细信息 包括自身属性和班级信息 而学生中的班级对象属性是无法赋值的 查询出来班级的数据要给学生属性班级对象的对应属性赋值
1. 级联方式处理映射关系
属性中对象的属性对应数据库中字段
<!-- List<Student> getAllStudent();-->
<resultMap id="getStudentMap" type="Student">
<id property="sid" column="sid"></id>
<result property="sname" column="sname"></result>
<result property="myClass.cid" column="cid"></result>
<result property="myClass.className" column="class_name"></result>
</resultMap>
<select id="getStudentMap" resultMap="getUserMap">
select student.* ,class.*
from t_student student
left join t_class class
on student.cid=class.cid
</select>
2. 使用association处理映射关系
<!-- List<Student> getAllStudentAssociation();-->
<!-- 类似于 嵌套了一个映射 第一层:属性对应的字段 第二层:属性中对象的属性对象的子段-->
<resultMap id="getStudentMapAss" type="Student">
<id column="sid" property="sid"></id>
<result column="sname" property="sname"></result>
<!-- association 处理实体类类型属性 注意javaType是设置对象属性的类型-->
<association property="myClass" javaType="MyClass">
<!-- 映射关系-->
<id column="cid" property="cid"></id>
<result column="class_name" property="className"></result>
</association>
</resultMap>
<select id="getAllStudentAssociation" resultMap="getStudentMapAss">
select student.*,class.*
from t_student student
left join t_class class
on student.cid=class.cid
</select>
1. 分步查询
1.先查询学生所有信息
studentMapper.xml:
<!-- List<Student> getStudent();-->
<resultMap id="getStudentMap" type="Student">
<id column="sid" property="sid"></id>
<result column="sname" property="sname"></result>
<result column="cid" property="cid"></result>
<!-- 要根据查询出的cid 调用ClassMapper的方法去根据cid查询出班级信息 返回拼接成完整信息-->
<!-- select:分步查询第二步的接口地址 column:要向接口中传递的数据是从数据库哪个字段中的数据-->
<association property="myClass" select="com.yan.mapper.MyClassMapper.getClassByCid" column="cid"></association>
</resultMap>
<select id="getStudent" resultMap="getStudentMap">
select *
from t_student
</select>
2. 根据学生信息中的cid去查询对应班级信息 最后进行组合即可查出所有详细信息
classMapper.xml
<!-- MyClass getClassByCid(@Param("cid") Integer cid);-->
<select id="getClassByCid" resultType="MyClass">
select *
from t_class
where cid=#{cid}
</select>
三种查询结果样式:另一个类包含在对象属性中
[Student{sid=1, sname='xiaoming', cid=1, myClass=MyClass{cid=1, className='班级1', students=null}}, Student{sid=2, sname='小红', cid=1, myClass=MyClass{cid=1, className='班级1', students=null}}]
一对多
与多对一不同的是 查询回来的是一个对象集合 一个集合不能点属性 没有级联查询
查询一个班级对应的所有学生
1. 使用collection 处理映射关系
对应上面多对一第二种方法 注意将**association->collection ,javaType->ofType**
<!-- List<MyClass> getAllClass();-->
<resultMap id="getAllMap" type="MyClass">
<id property="cid" column="cid"></id>
<result property="className" column="class_name"></result>
<collection property="students" ofType="Student">
<id column="sid" property="sname"></id>
<result column="sname" property="sname"></result>
</collection>
</resultMap>
<select id="getAllClass" resultMap="getAllMap">
select *
from t_class
left join t_student
on t_class.cid=t_student.cid
</select>
2. 分步查询
与多对一只有association->collection 不同
1. 先去获取班级全部信息
MyClassMapper.xml
```xml
<!-- List<MyClass> getAllClass();-->
<resultMap id="getAllMap" type="MyClass">
<id property="cid" column="cid"></id>
<result property="className" column="class_name"></result>
<collection property="students" select="com.yan.mapper.StudentMapper.getAllStudentByCid" column="cid"></collection>
</resultMap>
<select id="getAllClass" resultMap="getAllMap">
select *
from t_class
left join t_student
on t_class.cid=t_student.cid
</select>
```
2. 再由班级编号去学生表查询对应学生
studentMapper.xml
```xml
<!-- List<Student> getAllStudentByCid(@Param("cid")Integer cid);-->
<select id="getAllStudentByCid" resultType="student">
select *
from t_student
where cid=#{cid}
</select>
```
分步查询思路:
先去获取当前属性,对于对象属性在通过另一个条件查询 条件就在当前查询出的属性中
在xml绑定语句 指定条件
分步查询优点:
实现懒加载 例如:在查询一个学生信息时 时如不需要class的数据 将不执行第二条sql语句
前提:
在myabtis-config.xml中统一配置
<!--开启延时加载 按需加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="true"/>
或单独配置 在<association fetchType="lazy">
或<collection fetchType="lazy">
fetchType="lazy(延迟加载)|eager(立即加载)
一对多,多对一 补充:
注意sql语句左连接与右连接区别
左连接 交集和非交集
右连接:只有交集
动态sql
1. where if
动态添加where :如果if都不满足 省去where ;可省略(或补上)if语句中前方
的and
例:根据不确定个条件查询user
不使用where
<!-- List<User> getUserBy(@Param("id")Integer id,@Param("username") String username,@Param("email")String email);-->
<select id="getUserBy" resultType="User">
select *
from t_user
where 1=1
<if test="username!='' and username!=null">
and username=#{username}
</if>
<if test="email!='' and email!=null">
and email=#{email}
</if>
<if test="id!='' and id!=null">
and id=#{id}
</if>
</select>
使用where
<!-- List<User> getUserBy(@Param("id")Integer id,@Param("username") String username,@Param("email")String email);-->
<select id="getUserBy" resultType="User">
select *
from t_user
<where>
<if test="username!='' and username!=null">
username=#{username}
</if>
<if test="email!='' and email!=null">
email=#{email}
</if>
<if test="id!='' and id!=null">
id=#{id}
</if>
</where>
</select>
2. trim
trim用于去掉或添加标签中的内容
常用属性:
- prefix:在trim标签中的内容的
前面添加
某些内容 - prefixOverrides:在trim标签中的内容的
前面去掉
某些内容 - suffix:在trim标签中的内容的
后面添加
某些内容 - suffixOverrides:在trim标签中的内容的
后面去掉
某些内容
3. choose下的 when(if else if )、otherwise(else)
-
choose下只能有一个语句被选中
-
otherwise相当于else 不出现 或只在末尾出现一次
例:
<!-- List<User> getUserBy(@Param("id")Integer id,@Param("username") String username,@Param("email")String email);-->
<select id="getUserBy" resultType="User">
select *
from t_user
<where>
<choose>
<when test="id!='' and id!=null">
id=#{id}
</when>
<when test="username!='' and username!=null ">
username=#{username}
</when>
<otherwise>
id=15
</otherwise>
</choose>
</where>
</select>
4. foreach循环部分sql语句
要注意循环体内对象要加上#{}包裹
例 批量添加:
<!-- int addUserMore(@Param("Users") List<User> users);-->
<!-- collection:从接口接收过来的值 item:每一项 separator:每次循环的分隔符 -->
<insert id="addUserMore">
insert into t_user
values
<foreach collection="users" item="user" separator=",">
( null,#{user.username},null)
</foreach>
</insert>
转变成jdbc形式是
insert into t_user values ( null,?,null) , ( null,?,null) , ( null,?,null)
例批量删除
<!-- int delByIds(@Param("ids") Integer[] ids);-->
<delete id="delByIds">
delete
from t_user
where id
in
-- open:在整体的循环前面加上 close :在整体循环后面加上
<foreach collection="ids" separator="," item="id" open="(" close=")">
#{id}
</foreach>
</delete>
5. sql片段 +include去引用
相当于将常用的sql部分片段定义为一个常量 在sql语句中去引用增加sql部分代码通用性
例: 原形式:
<!-- List<User> getUser();-->
<select id="getUser" resultType="User">
select id,username from t_user
</select>
使用<sql>
改造后
<sql id="idAndUsername">
id,username
</sql>
<!-- List<User> getUser();-->
<select id="getUser" resultType="User">
select <include refid="idAndUsername"></include> from t_user
</select>
一、二级缓存
1. 一级缓存
一级缓存默认开启,是sqlSession级别的 (只有同一个sqlSession才有效)
测试:
注意 同一个session下 连着相同查询 第二次没有访问数据库直接返回结果
缓存不可用两种情况:
1. 不同的session 虽是相同的查询但不同的session去调用依然不可用 但之前的缓存还在
2. 同一个session 调用不同的语句 即使sql语句相同 也不能使用缓存
缓存清空两种情况:
· 1. 两次相同的查询有之间有任何一次对表的增删改(即使没有修改成功)
·
2. 手动清除 sqlSession.clearCache()
2. 二级缓存
二级缓存需要手动开启,作用于整个sqlSessionFactory级别 要保证是同一个sqlSessionFactory提供
二级缓存开启数据会现从二级中查找,再去一级缓存,最后数据库
二级缓存使用方式
- 在mybatis-config.xml中 设置全局配置属性cacheEnabled=“true”,默认为true,不需要设置
- 在xxxMaper.xml中 添加
<cache/>
- 在使用时 必须将seesion关闭才生效
sqlSession.close();
- 用到的实体类必须序列化
implements Serializable
在测试过程中发现 使用这种工具类 每次获取一个seqlSession都会创建一个sqlSessionFactory 无法保证 是同一个sqlSessionFactory提供
static public SqlSession getSqlSession() throws IOException {
// 读取配置文件
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
// SqlSessionFactoryBuilder 读取配置文件创造 sqlSessionFactory
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
// 工厂创造一个个具体的sqlSession 返回
// 扩号内 true:事务自动提交 false:手动提交 最后执行 commit()
return sqlSessionFactory.openSession(true);
}
测试
不同的sqlSession调用同一个接口
@Test
public void selectUser() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
// 同一个工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
// 创建两个sqlSession
SqlSession sqlSession1 = sessionFactory.openSession(true);
SqlSession sqlSession2= sessionFactory.openSession(true);
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
System.out.println(mapper1.selectUser());
// 一定要提交sqlSession
sqlSession1.close();
System.out.println(mapper2.selectUser());
sqlSession2.close();
}
使得二级缓存清空只能是 在此期间发生对表的修改(sqlSession.clear()无效)
补充
在cache中可选缓存策略 <cache/>
eviction属性:缓存回收策略,默认的是 LRU。
- LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。
- FIFO(First in Firstout) – 先进先出:按对象进入缓存的顺序来移除它们。
整合第三方二级缓存EHCache
使用步骤:
- 导入依赖:
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.1</version>
</dependency>
- 创建Ehcache配置文件ehcache.xml(文件名固定)
<?xml version="1.0" encoding="utf-8" ?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<!-- 磁盘保存路径 -->
<diskStore path="D:\ehcache"/>
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
- 将XxxMapper.xml 中的cache标签设置为
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
引入对应日志(原来日志不能打印)
1. pom文件
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
- 创建logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
<!-- 指定日志输出的位置 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- 日志输出的格式 -->
<!-- 按照顺序分别是: 时间、日志级别、线程名称、打印日志的类、日志主体内容、换行 -->
<pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern>
</encoder> </appender>
<!-- 设置全局日志级别。日志级别按顺序分别是: DEBUG、INFO、WARN、ERROR -->
<!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
<root level="info">
<!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender -->
<appender-ref ref="STDOUT" />
</root>
<!-- 根据特殊需求指定局部日志级别 -->
<logger name="com.yan.mapper" level="DEBUG"/> </configuration>
代码上没有变化 效果相同
mybatis逆向工程(由数据库生成java模板代码
根据配置的数据库表自动生成pojo实体类、mapper接口、Mapper.xml
使用方式:
- 在pom文件中引用插件
<build>
<!-- 构建过程中用到的插件 -->
<plugins>
<!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.0</version>
<!-- 插件的依赖 -->
<dependencies>
<!-- 逆向工程的核心依赖 -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency> <!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency> </dependencies>
</plugin>
</plugins>
</build>
- 创建逆向工程的配置文件
generatorConfig.xml
(文件名写死)如下: - 点击对应maven插件,自动生成
1. 简化模板
在mapper中只提供了5种操作
主要作用是根据表创建对应结构,业务仍需自己写sql
<?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">
<generatorConfiguration>
<!-- targetRuntime: 执行生成的逆向工程的版本
MyBatis3Simple: 生成基本的CRUD(清新简洁版)
MyBatis3: 生成带条件的CRUD(奢华尊享版) -->
<context id="DB2Tables" targetRuntime="MyBatis3Simple">
<!-- 数据库的连接信息 -->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC"
userId="root"
password="1234">
</jdbcConnection>
<!-- targetPackage 指定生成的model生成所在的包名-->
<!-- targetProject 指定在该项目下所在的路径-->
<!-- Pojo的生成策略-->
<javaModelGenerator targetPackage="com.yan.pojo"
targetProject=".\src\main\java">
<!-- 是否允许子包 -->
<property name="enableSubPackages" value="true"/>
<!-- 是否对类CHAR类型的列的数据进行trim操作 -->
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- mapper的生成策略 -->
<sqlMapGenerator targetPackage="com.yan.mapper"
targetProject=".\src\main\resources">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!-- xml-->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.yan.mapper"
targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!-- 逆向分析的表 -->
<!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
<!-- domainObjectName属性指定生成出来的实体类的类名 -->
<table tableName="t_user" domainObjectName="Userqwqw"/>
</context>
</generatorConfiguration>
2. 标准模板
采用了MBG风格 提供了大量的封装sql的方法 简单业务只需要调用方法
将<context id="DB2Tables" targetRuntime="MyBatis3Simple">
中的MyBatis3Simple 替换成 MyBatis3
重新点击创建
相较于简易型在pojo多了 Example用于向mapper中传递条件
例:
@Test
public void getTest() throws IOException {
TestMapper mapper = GetSqlSession.getSqlSession().getMapper(TestMapper.class);
// example中封装了条件
TestExample example = new TestExample();
example.createCriteria().getAllCriteria();
// 在mapper中传入条件
System.out.println(mapper.selectByExample(example));
}
例:
生成的pojo没有有参构造函数
@Test
public void getTest() throws IOException {
TestMapper mapper = GetSqlSession.getSqlSession().getMapper(TestMapper.class);
// example中封装了条件
TestExample example = new TestExample();
// 条件为:name为aa 并且id为1 或者name为bb 注意 or() 使用要换行
example.createCriteria().andNameEqualTo("aa").andIdEqualTo(1);
example.or().andNameEqualTo("bb");
// 在mapper中传入条件
// 修改的两种方式
// 1、 只有指明的地方才会修改,其余保持不变
mapper.updateByExampleSelective(new com.yan.pojo.Test(100,"cc"),example);
// 2、 指明的修改,其余修改为null
// mapper.updateByExample(new com.yan.pojo.Test(100,"cc"),example);
}
分页插件
有了分页插件 ,返回分页信息更细致 ,分页查询更方便
插件会拦截数据库请求 ,加上limit 所以注意xml中sql语句写完不要加;
在所有查询结果中截取
使用
- 带入pom依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
- 在mybatis-config.xml的
<environments >
标签上方导入
<plugins>
<!--设置分页插件-->
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
测试:
@Test
public void getUser() throws IOException {
UserMapper mapper = GetSqlSession.getSqlSession().getMapper(UserMapper.class);
// 开启分页 自动获取查询数据
Page<Object>page =PageHelper.startPage(2,3);
List<User> users = mapper.selectUser();
// users已经在page中
System.out.println(page);
// PageInfo 放在查询后面 数据更加详细
// 第二个参数,显示有几个的页码的数据
PageInfo<User> pageInfo = new PageInfo<>(users, 2);
System.out.println(pageInfo);
}
变量说明:
pageNum:当前页的页码
pageSize:每页显示的条数
size:当前页显示的真实条数
total:总记录数
pages:总页数
prePage:上一页的页码
nextPage:下一页的页码
isFirstPage/isLastPage:是否为第一页/最后一页
hasPreviousPage/hasNextPage:是否存在上一页/下一页
navigatePages:导航分页的页码数
navigatepageNums:导航分页的页码