MyBatis开发文档:
mybatis - MyBatis 3mybatis.orgmapper接口开发的四个规范:
XxxMapper.xml配置文件的名称命名空间值必须是mapper接口的全类名
- XxxMapper.xml配置文件中id值必须是接口中的方法名
- XxxMapper.xml配置文件中的parameterType参数类型必须和接口的方法参数类型一致
- XxxMapper.xml配置文件中的resultType返回值类型必须和接口的方法返回值类型一致(JavaBean才有需要)
遵守规范之后,可以不用写接口实现类
XML配置:
<settings>设置自动驼峰命名规则映射作用在于在数据库列名有下划线等特殊字符时,会自动去掉后的第二个首字母大写来取代别名的设置
没有设置:
类型别名(typeAliases)
类型别名是为 Java 类型设置一个短的名字。 它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余。例如:
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
<typeAlias alias="Comment" type="domain.blog.Comment"/>
<typeAlias alias="Post" type="domain.blog.Post"/>
<typeAlias alias="Section" type="domain.blog.Section"/>
<typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
<typeAliases>
<package name="com.review.DynamicSql.domain"/>
</typeAliases>
XML映射文件:
1.#{}和${}的区别:
#{}是占位符 =====>>> ?
${}是把表示的参数值原样输出,然后和sql语句的字符串做拼接操作,${value}里面必须是value,不能是其他的值,除非设置param注解之后,写注解里的内容
代码如下:
//接口:
//根据姓名模糊查询
public List<User> queryUsersLikeName(String name);
//xml配置文件:
<select id="queryUsersLikeName" resultType="user">
<!--select id,last_name,sex from t_user where last_name like #{param1};-->
select id,last_name,sex from t_user where last_name like '%${value}%';
</select>
//测试:
@Test
public void testQueryUsersLikeName(){
SqlSession session = sqlSessionFactory.openSession();
UserDao mapper = session.getMapper(UserDao.class);
try {
String name="vin";
mapper.queryUsersLikeName(name).forEach(System.out::println);
}finally {
session.close();
}
}
2.可以使用concat很好的解决模糊查询的问题
<select id="queryUsersLikeName" resultType="user">
select id,last_name,sex from t_user where last_name like concat('%',#{name},'%");
</select>
3.resultMap标签的作用
<resultMap/>标签可以把可以把查询到的resultSet结果集转换成为复杂的JavaBean对象。
原来的resultType属性只能把查询到的结果集转换成为简单的javaBean对象
所谓简单的javaBean对象:是指它的属性里没有javaBean或集合类型的对象,反之亦然。
//代码举例如下:
//javaBean:
public class Key {
private Integer id;
private String name;
private Lock lock;
}
public class Lock {
private Integer id;
private String name;
}
//接口:
public interface KeyMapper {
public Key queryKeyByIdForSample(Integer id);
}
//xml配置文件:
<mapper namespace="com.review.mybatisResultMap.dao.KeyMapper">
<!-- public Key queryKeyByIdForSample(Integer id);-->
<!--
resultMap标签可以把查询到的resultSet结果集转换成为复杂的JavaBean对象
type属性:设置resultMap需要转换出来的Bean对象的全类名
id属性:设置一个唯一的标识,给别人应用
-->
<resultMap id="queryKeyByIdForSample_resultMap" type="key">
<!--
id标签负责把主键列转换到bean对象的属性
column属性:设置将数据库中的哪个主键列转换到指定的对象属性中
property属性:设置将值注入到哪个对象的属性中
-->
<id column="id" property="id"></id>
<!--
result标签负责把非主键列转换到bean对象的属性
-->
<result column="name" property="name"></result>
<!--
association标签映射子对象
property属性:设置association配置哪个子对象
javaType属性:设置association配置子对象的具体全类名
-->
<association property="lock" javaType="lock">
<id column="lock_id" property="id"></id>
<result column="lock_name" property="name"></result>
</association>
<!--
将lock_id列注入到lock对象的id属性中
写法:子对象.属性名 这种写法叫级联属性
-->
<!-- <result column="lock_id" property="lock.id"></result>-->
<!-- <result column="lock_name" property="lock.name"></result>-->
</resultMap>
<select id="queryKeyByIdForSample" resultMap="queryKeyByIdForSample_resultMap">
select t_key.*,t_ock.name lock_name
from t_key left join t_lock
on t_key.lock_id=t_lock.id
where t_key.id=1;
</select>
</mapper>
4.<association />标签作用
<mapper namespace="com.review.mybatisResultMap.dao.LockMapper">
<!--public Lock queryLockById(Integer id);-->
<select id="queryLockById" resultType="lock">
select id,name from t_lock where id=#{id};
</select>
</mapper>
<association />标签可以实现分步查询
<resultMap id="queryKeyByIdForStep_resultMap" type="key">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<association property="lock" column="lock_id"
<!--select标签里的内容是:另外一张关联表对应接口的包路径.sql语句的id属性-->
select="com.review.mybatisResultMap.dao.LockMapper.queryLockById"/>
</resultMap>
<select id="queryKeyByIdForStep" resultMap="queryKeyByIdForStep_resultMap">
select id,name,lock_id from t_key where id=#{id};
</select>
</mapper>
动态SQL
标签中的test条件的值是设置Param注解的属性名称
<if/>标签:用来判断一个条件是否成立,成立就执行
<where/>标签: 可以动态的去掉包含在内容前面的and、or关键字
<trim/> 标签:通过自定义 trim 元素来定制 where 元素的功能
trim的属性:
prefix 添加前缀
prefixOverrides 删除前缀
suffix 添加后缀
suffixOverrides 删除后缀
//Javabean类
public class User {
private Integer id;
private String lastName;
private Integer sex;
//接口
/**
* 根据名称和性别查询
* 希望lastName值不能为Null,性别只能是0,1有效值
*/
public List<User> queryUserForNameAndSex(@Param("name") String name, @Param("sex") Integer sex);
<mapper namespace="com.review.DynamicSql.dao.UserMapper">
<!-- /**-->
<!-- * 根据名称和性别查询-->
<!-- */-->
<!-- public List<User> queryUserForNameAndSex();-->
<select id="queryUserForNameAndSex" resultType="user">
select
id,last_name,sex
from
t_user
<!--
where标签可以动态的去掉包含在内容前面的and、or关键字
if标签用来判断一个条件是否成立,成立就执行
-->
<trim suffixOverrides="and" prefix="where">
<if test="name!=null">
last_name like concat('%',#{name},'%') and
</if>
<if test="sex==0||sex==1">
sex=#{sex};
</if>
</trim>
</select>
</mapper>
<choose/>,<when/>,<otherwise/>标签
choose标签是按顺序判断其内部when标签中的test条件出否成立,如果有一个成立,则 choose 结束。当 choose 中所有 when 的条件都不满则时,则执行 otherwise 中的sql。类似于Java 的 switch 语句,choose 为 switch,when 为 case,otherwise 则为 default。
<!-- /**-->
<!-- * 如果lastName有值,则使用它查询-->
<!-- * 如果lastName没有值,sex值有效,则使用sex值查询-->
<!-- * 否则,自己添加一个查询条件-->
<!-- */-->
<!-- public List<User> queryUserByNameAndSexChoose(User user);-->
<select id="queryUserByNameAndSexChoose" resultType="user">
select id,last_name,sex
from t_user
<where>
<choose>
<when test="lastName!=null">
last_name like concat('%',#{lastName},'%')
</when>
<when test="sex==0||sex==1">
sex=#{sex}
</when>
<otherwise>
last_name='jack' and sex=1
</otherwise>
</choose>
</where>
</select>
<set>标签:删除条件后的逗号
<!--public int updateUser(User user);-->
<update id="updateUser" parameterType="user" >
update
t_user
<set>
<if test="lastName!=null">
last_name=#{lastName},
</if>
<if test="sex==1||sex==0">
sex=#{sex}
</if>
</set>
<where>
id=#{id};
</where>
</update>
<foreach/>标签:对一个集合进行遍历,通常是在构建 IN 条件语句的时候
<foreach/>属性值:
collection:你要遍历的数据源(必须是list)
item:表示当前遍历的数据,取一个名称
open:表示遍历之前添加的元素
close:表示遍历之后添加的元素
separator:给遍历的每个元素中间添加的内容
<!-- public List<User> queryUserByIdForeach(List<Integer> ids);-->
<select id="queryUserByIdForeach" resultType="user">
select
id,last_name,sex
from
t_user
where
id in
<!--
foreach遍历输出:
collection:你要遍历的数据源(必须是list)
item:表示当前遍历的数据,取一个名称
open:表示遍历之前添加的元素
close:表示遍历之后添加的元素
separator:给遍历的每个元素中间添加的内容
-->
<foreach collection="list" item="i" open="(" close=")" separator=",">
#{i}
</foreach>
</select>
Mybatis缓存
缓存的使用顺序说明:
- 每执行一次查询,首先会到二级缓存中去查看有没有数据,如果二级缓存中没有,再到一级缓存中去查看有没有数据
- 如果都没有,发送sql语句到数据库中去查询,把结果放到一级缓存中。
- 当关闭SqlSession的时候一级缓存同步到二级缓存中。
缓存:
- 缓存是指把经常需要读取的数据保存到一个高速缓冲区中,这个行为叫缓存。
- 缓存也可以是指被保存到高速缓冲区中的数据,也叫缓存。
一级缓存:是指把数据保存到SqlSession中
二级缓存:是指把数据保存到SqlSessionFactory中
![f7050aab18e509416326aeaa657270ee.png](https://i-blog.csdnimg.cn/blog_migrate/1183439d12f246e41eea1b69fd75fa5c.jpeg)
对一级缓存的理解:在测试类中测试查询语句时,首先到一级缓存中去查询是否有该数据,如果缓存中有就直接返回,没有的话发送sql语句到数据库中去查询,把查到的结果保存在缓存中,下次查询该语句时,直接从缓存中拿数据返回。
一级缓存有失效的四种情况:
1.不在同一个SqlSession对象中
public void testFailCache1(){
// 不在同一个SqlSession对象中
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
System.out.println(mapper.queryUserById(2));
}finally {
session.close();
}
}
@Test
public void test1(){
testFailCache1();
testFailCache1();
}
2.执行语句的参数不同.缓存中也不存在数据
@Test
public void testFailCache2(){
//执行语句的参数不同.缓存中也不存在数据
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
System.out.println(mapper.queryUserById(2));
System.out.println(mapper.queryUserById(10));
}finally {
session.close();
}
}
3.执行增,删,改语句,会清空缓存
@Test
public void testFailCache3(){
//执行增,删,改语句,会清空缓存
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
System.out.println(mapper.queryUserById(2));
mapper.updateUser(new User(12,"mark",0));
session.commit();
System.out.println(mapper.queryUserById(2));
}finally {
session.close();
}
4.手动清空缓存数据
@Test
public void testFailCache4(){
//手动清空缓存数据
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
System.out.println(mapper.queryUserById(2));
session.clearCache();
System.out.println(mapper.queryUserById(2));
}finally {
session.close();
}
}
二级缓存的使用:
mybatis的二级缓存默认是不开启的
- 我们需要在mybatis的核心配置文件中配置setting选项
<setting name="cacheEnabled" value="true"/>
2.在Mapper的配置文件中加入cache标签
<cache/>
3.并且需要被二级缓存的对象必须要实现java的序列号接口
public class User implements Serializable {
private Integer id;
private String lastName;
private Integer sex;
}
![a65ea1c0da3fb2abadc9214cafd1651d.png](https://i-blog.csdnimg.cn/blog_migrate/0158e64d02b817e7a11d04c51a1cfb9d.jpeg)
- useCache属性的作用:在select标签中,useCache属性表示是否使用二级缓存。默认是true,使用二级缓存。(每次查询完后,也会把这个查询的数据放到二级缓存中)
<select id="queryUserById" resultType="user" useCache="true">
select id,last_name,sex from t_user where id = #{id};
</select>
- update 的时候如果 flushCache="false",则当你更新后,查询的数据数据还是老的数据。因为是从缓存中拿的数据,并没有去数据库中查询来实时更新。flushCache默认是true。
<update id="updateUser" parameterType="user" flushCache="true">
update t_user set last_name=#{lastName},sex=#{sex} where id=#{id};
</update>
@Test
public void testTwoCache(){
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
System.out.println(mapper.queryUserById(2));
mapper.updateUser(new User(2,"vans",0));
session.commit();
System.out.println(mapper.queryUserById(2));
}finally {
session.close();
}
}
mybatis逆向工程
MyBatis逆向工程,简称MBG。是一个专门为MyBatis框架使用者定制的代码生成器。可以快速的根据表生成对应的映射文件,接口,以及Bean类对象。
在MyBatis中,有一个可以自动对单表生成增、删、改、查代码的插件:mybatis-generator-core.
MyBatis逆向工程在Idea中的使用步骤:
- 新建一个maven工程,导入一下包
<dependencies>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.26</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
2.新建一个MyBatis Generator(MBG)的XML配置文件驱动,放在main目录下。
<?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表示你要生成的版本
MyBatis3:豪华版本
MyBatis3Simple:CRUD标准版
-->
<context id="DB2Tables" targetRuntime="MyBatis3Simple">
<!--去掉全部注释-->
<commentGenerator>
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis_mbg"
userId="root"
password="123456">
</jdbcConnection>
<javaTypeResolver >
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!--
javaModelGenerator配置生成JavaBean
targetPackage生成的javaBean的包名
targetProject生成之后在哪个工程目录下
-->
<javaModelGenerator targetPackage="com.review.mybatisMbg.domain" targetProject="src/main/java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!--
sqlMapGenerator生成sql的mapper.xml配置文件
targetPackage生成的mapper.xml配置文件放的包名
-->
<sqlMapGenerator targetPackage="com.mybatisMbg.mapper" targetProject="src/main/resources">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!--配置生成的mapper接口-->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.review.mybatisMbg.mapper" targetProject="src/main/java">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!--一个table标签,一个表-->
<table tableName="t_user" domainObjectName="User" ></table>
<table tableName="t_book" domainObjectName="Book" ></table>
</context>
</generatorConfiguration>
3.导入mybatis-config.xml配置文件,放在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>
<settings>
<!--
是否开启自动驼峰命名规则(camel case)映射,
即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。
-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>
<!--
别名设置
-->
<typeAliases>
<package name="com.review.mybatisMbg.domain"/>
</typeAliases>
<!--配置环境-->
<environments default="mysql">
<environment id="mysql">
<!--配置事务类型-->
<transactionManager type="JDBC"></transactionManager>
<!--数据连接池-->
<dataSource type="POOLED">
<!--配置连接数据库的四个信息-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis_mbg"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--指定映射文件位置,映射文件是每个dao独立配置的文件-->
<mappers>
<mapper resource="com/mybatisMbg/mapper/BookMapper.xml"></mapper>
</mappers>
</configuration>
4.写一个java类,将转换执行代码写进去。File文件一定要写MyBatis Generator(MBG)的XML配置文件驱动名称
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("src/main/mbg.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);