尚硅谷:https://www.bilibili.com/video/BV1Ya411S7aT?share_source=copy_web
Mybatsi简介
Mybatis历史
前身iBatis。iBatis是一个基于Java的持久层框架。iBatis提供的持久层框架包括SQL Maps和DataAccessObjects(DAO)。
SQLMaps:SQL映射,即将Java的实体类对象映射为数据库中的一条数据,或数据库的一条记录查询为Java中的实体类对象
Mybatis特性
-
支持定制化SQL、存储过程以及高级映射的优秀的持久层框架
-
避免了几乎所有的JDBC代码和手动设置参数以及获取结果集
-
可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO映射成数据库中的记录
-
是一个半自动的ORM(Object Relation Mapping)框架
Mybatis的配置
导入依赖
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.13</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.2</version>
</dependency>
</dependencies>
创建核心配置文件(连接数据库)
<?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>
<!--引入配置文件,此后就可以在当前文件中使用${key}的方式访问value-->
<properties resource="jdbc.properties"/>
<!--
设置别名
alias:别名。可以不写
不区分大小写
-->
<typeAliases>
<!--<typeAlias type="com.zwb.pojo.User"/>-->
<!--将包下所有的类起别名-->
<package name="com.zwb.pojo"/>
</typeAliases>
<!--
environments:配置连接数据库的环境
属性:
default:设置默认使用环境
id:设置环境的唯一标识,不能重复
-->
<!--配置连接数据库的环境-->
<environments default="propertiesTest">
<environment id="development">
<!--
transactionManager:设置事务管理器
属性:
type:设置事务管理方式
type="JDBC|MANAGED"
JDBC:表示使用JDBC中原生的事务管理方式
MANAGED:被管理,例如Spring
-->
<transactionManager type="JDBC"/>
<!--
dataSource:设置数据源
属性:
type:设置数据源的类型
type="POOLED|UNPOOLED|JNDI"
POOLED:表示使用数据库连接池
UNPOOLED:表示不使用数据库连接池
JNDI:表示使用上下文中的数据源
-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8&serverTimezone=UTC&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
<environment id="propertiesTest">
<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>
<!--引入mybatis的映射文件-->
<mappers>
<!--<mapper resource="com/zwb/mapper/UserMapper.xml"/>-->
<package name="com.zwb.mapper"/>
</mappers>
</configuration>
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC
jdbc.username=root
jdbc.password=123456
<!--引入配置文件,此后就可以在当前文件中使用${key}的方式访问value--> <properties resource="jdbc.properties"/>
<!--设置别名 不区分大小写--> <typeAliases> <!--<typeAlias type="com.zwb.pojo.User"/>--> <!--将包下所有的类起别名--> <package name="com.zwb.pojo"/> </typeAliases>
<!-- 以包的方式引入映射文件 1.mapper接口和映射文件所在的包必须一致 2.mapper接口的名字和映射文件的名字必须一致 --> <package name="com.zwb.mapper"/>
创建mapper接口
mapper接口相当于以前的dao。区别在于,mapper仅仅是接口,不需要提供实现类
public interface UserMapper {
int insertUser();
}
创建映射文件
ORM:对象关系映射
-
对象:Java的实体类对象
-
关系:关系型数据库
-
映射:二则之间的关系
Java概念 | 数据库概念 |
---|---|
类 | 表 |
属性 | 字段/列 |
对象 | 记录/行 |
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace=绑定一个对应的Mapper接口-->
<mapper namespace="com.zwb.mapper.UserMapper">
<!--
mapper接口和映射文件要保证两个一致
1.mapper接口和映射文件的namespace一致
2.mapper接口的方法名要和映射文件sql的id保持一致
-->
<!--id为接口里的方法名,resultType为sql语句的返回值-->
<!--int insertUser();-->
<insert id="insertUser">
insert into t_user values(null,'admin','123456',23,'男','[email protected]')
</insert>
</mapper>
测试
@Test
public void testInsert() throws IOException {
// 获取核心配置文件的输入流
InputStream is =Resources.getResourceAsStream("mybatis-config.xml");
//获取SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder=new SqlSessionFactoryBuilder();
//获取SqlSeesionFactory对象
SqlSessionFactory sqlSessionFactory=sqlSessionFactoryBuilder.build(is);
//获取sql的会话对象SqlSession,是Mybatis提供的操作数据库的对象
//SqlSession sqlSession=sqlSessionFactory.openSession();//不会自动提交事务
SqlSession sqlSession=sqlSessionFactory.openSession(true);//自动提交事务
//获取UserMapper的代理实现类对象
UserMapper mapper=sqlSession.getMapper(UserMapper.class);
int result=mapper.insertUser();
//提交事务
//sqlSession.commit();
System.out.println(result);
sqlSession.close();
}
SqlSession:代表Java程序和数据库之间的会话。(HttpSeesion是Java程序和浏览器之间的会话)
SqlSessionFactory:是“生产”SqlSession的“工厂”
工厂模式:如果创建一个对象,使用的过程基本固定,那就可以把创建这个对象的相关代码封装到一个“工厂类”中,以后都使用这个工厂类来“生产”需要的对象
封装SqlSession创建流程
public class SqlSessionUtil {
public static SqlSession getSqlSession() {
SqlSession sqlSession=null;
try{
//获取核心配置文件的输入流
InputStream is=Resources.getResourceAsStream("mybatis-config.xml");
//获取SqlSessionFactroyBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder=new SqlSessionFactoryBuilder();
SqlSessionFactory sessionFactory=sqlSessionFactoryBuilder.build(is);
sqlSession=sessionFactory.openSession(true);
}catch (IOException e){
e.printStackTrace();
}
return sqlSession;
}
}
CRUD
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace=绑定一个对应的Mapper接口-->
<mapper namespace="com.zwb.mapper.UserMapper">
<!--
mapper接口和映射文件要保证两个一致
1.mapper接口和映射文件的namespace一致
2.mapper接口的方法名要和映射文件sql的id保持一致
-->
<!--id为接口里的方法名,resultType为sql语句的返回值-->
<!--int insertUser();-->
<insert id="insertUser">
insert into t_user values(null,'admin','123456',23,'男','[email protected]')
</insert>
<!--updateUser()-->
<update id="updateUser">
update t_user set username='root',password='123' where id=3
</update>
<!-- deleteUser-->
<delete id="deleteUser">
delete from t_user where id=3
</delete>
<!--
resultType:设置结果类型,即查询的数据要转换的java类型
resultMap:自定义映射,处理一对多或多对一的映射关系
-->
<!--getUserById-->
<select id="getUserById" resultType="com.zwb.pojo.User">
select * from t_user where id=1
</select>
<!--getAllUser()-->
<select id="getAllUser" resultType="com.zwb.pojo.User">
select * from t_user
</select>
</mapper>
public interface UserMapper {
int insertUser();
int updateUser();
int deleteUser();
User getUserById();
List<User> getAllUser();
}
@Test
public void testInsert() throws IOException {
// 获取核心配置文件的输入流
InputStream is =Resources.getResourceAsStream("mybatis-config.xml");
//获取SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder=new SqlSessionFactoryBuilder();
//获取SqlSeesionFactory对象
SqlSessionFactory sqlSessionFactory=sqlSessionFactoryBuilder.build(is);
//获取sql的会话对象SqlSession,是Mybatis提供的操作数据库的对象
//SqlSession sqlSession=sqlSessionFactory.openSession();//不会自动提交事务
SqlSession sqlSession=sqlSessionFactory.openSession(true);//自动提交事务
//获取UserMapper的代理实现类对象
UserMapper mapper=sqlSession.getMapper(UserMapper.class);
int result=mapper.insertUser();
//提交事务
//sqlSession.commit();
System.out.println("结果:"+result);
sqlSession.close();
}
@Test
public void UpdateTest(){
SqlSession sqlSession= SqlSessionUtil.getSqlSession();
UserMapper mapper=sqlSession.getMapper(UserMapper.class);
mapper.updateUser();
sqlSession.close();
}
@Test
public void deleteUser(){
SqlSession sqlSession=SqlSessionUtil.getSqlSession();
UserMapper mapper=sqlSession.getMapper(UserMapper.class);
mapper.deleteUser();
sqlSession.close();
}
@Test
public void getUserByIdTest(){
SqlSession sqlSession=SqlSessionUtil.getSqlSession();
UserMapper mapper=sqlSession.getMapper(UserMapper.class);
System.out.println(mapper.getUserById());
sqlSession.close();
}
@Test
public void geAlltUserTest(){
SqlSession sqlSession=SqlSessionUtil.getSqlSession();
UserMapper mapper=sqlSession.getMapper(UserMapper.class);
System.out.println(mapper.getAllUser());
sqlSession.close();
}
Mybatis获取参数值的两种方式
Mybatis或取参数的两种方式:${}和#{}
-
${}的本质就是字符串的拼接
-
使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需手动加单引号
-
-
#{}本质就是占位符的赋值
-
占位符赋值的方式拼接sql,此时为字符串类型和日期类型的字段进行赋值时,可自动添加单引号
-
单个字面量类型的参数
若mapper接口中的方法参数为单个字面量类型,此时可以使用${}和#{}获取参数的值,注意${}需要手动加单引号
<select id="getUserByUsername" resultType="user">
<!--select * from t_user where username=#{name}-->
select * from t_user where username='${username}'
</select>
多个字面量类型的参数
若mapper接口的方法参数为多个时
此时Mybatis会自动将这些参数放在一个map集合中,以arg0,arg1...为键,以参数为值;以param1,...为键,以参数为值;因此只需通过${}和#{}访问集合的键就可以获取值
<!--checkLogin(String username,String password)-->
<select id="checkLogin" resultType="User">
<!--select * from t_user where username=#{param1} and password=#{param2}-->
select * from t_user where username='${param1}' and password='${param2}'
</select>
User checkLogin(String username,String password);
自定义map
User checkLoginByMap(Map<String,Object> map);
Map<String,Object> map=new HashMap<>();
map.put("username","admin");
map.put("password","123456");
User user=mapper.checkLoginByMap(map);
<!--User checkLoginByMap(Map<String,Object> map);-->
<select id="checkLoginByMap" resultType="User">
<!--select * from t_user where username=#{param1} and password=#{param2}-->
select * from t_user where username='${username}' and password='${password}'
</select>
</mapper>
实体类
void insertUser(User user);
<insert id="insertUser">
insert into t_user values(null,#{username},#{password},#{age},#{gender},#{email})
</insert>
注解@Param()
User checkLoginByParam(@Param("username") String username,@Param("password") String password);
<select id="checkLoginByParam" resultType="User">
<!--select * from t_user where username=#{username} and password=#{password}-->
select * from t_user where username='${username}' and password='${password}'
</select>
[password, param1, username, param2]
注解会将map集合中的arg0...替换为自定义的名称
Mybatis的各种查询
查询一个实体类对象
/**
* 根据id查询
* @param id
* @return
*/
User getUserById(@Param("id") Integer id);
<!--User getUserById(Integer id);-->
<select id="getUserById" resultType="User">
select * from t_user where id=#{id}
</select>
查询一个list集合
/**
* 查询所有用户
* @return
*/
List<User> getAllUser();
<!--List<User> getAllUser()-->
<select id="getAllUser" resultType="User">
select * from t_user
</select>
查询单个数据
/**
* 查询用户数
*/
Integer getCount();
<select id="getCount" resultType="Integer">
select COUNT(*) from t_user
</select>
查询一条数据为map集合
/**
* 根据id查询用户信息为map集合
* @param id
* @return
*/
Map<String,Object> getUserByIdToMap(@Param("id") Integer id);
<!--getUserByIdToMap(@Param("id") Integer id)-->
<select id="getUserByIdToMap" resultType="map">
select * from t_user where id=#{id}
</select>
查询多条数据为map集合
/**
* 查询所有的用户信息为一个Map集合
* 若查询返回结果有多条时,又要将结果存入map集合时,有两种解决方案
* 1.将mapper接口返回值设置为泛型是map的list集合
* 2.通过注解@MapKey(),以某个字段为键,其余数据为值,组成map的键值对
* @return
*/
// List<Map<String,Object>> getAllUserToMap();
@MapKey("id")//以id为键,其余数据为值,组成map的键值对
Map<String,Object> getAllUserToMap();
<!--getAllUserToMap()-->
<select id="getAllUserToMap" resultType="map">
select * from t_user
</select>
查询的结果有实体类,用实体类对象接收
查询的结果无实体类,用map集合方式接收
Mybatis为Java的常用类型设置了别名 Integer:int,Integer int:int,integer Map:map String:string
特殊SQL的执行
模糊查询
/**
* 通过用户名模糊查询用户信息
* @param fuzzy
* @return
*/
List<User> getUserByLike(@Param("fuzzy")String fuzzy);
<select id="getUserByLike" resultType="User">
<!--select * from t_user where username like '%${fuzzy}%'-->
<!--select * from t_user where username like concat('%',#{fuzzy},'%')-->
select * from t_user where username like "%"#{fuzzy}"%"
</select>
'%#{}%'无法使用,因为#{}是占位符,会被识别为字符串
批量删除
/**
* 拼接多个id传入,实现批量删除
* @param ids
*/
void deleteMoreUser(@Param("ids") String ids);
<!--deleteMoreUser(@Param("ids") String ids)-->
<delete id="deleteMoreUser">
delete from t_user where id in(${ids})
</delete>
不能使用#{},因为会自动在字符串两侧添加''
动态设置表名
/**
* 动态设置表名,查询用户信息
* @param tableName
* @return
*/
List<User> getUserList(@Param("tableName")String tableName);
<!--getUserList(@Param("tableName")String tableName)-->
<select id="getUserList" resultType="User">
select * from ${tableName}
</select>
不能使用#{},因为会自动在字符串两侧添加'',而表名不能有''
获取自增id
在实现添加功能后,可以立刻获取自增的id
/**
* 添加用户信息,并获取自增的主键
* @param user
*/
void insertUser(User user);
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
insert into t_user value(null,#{username},#{password},#{age},#{gender},#{email})
</insert>
@Test
public void testInsertUser(){
SqlSession sqlSession= SqlSessionUtil.getSqlSession();
SpecialSQLMapper specialSQLMapper=sqlSession.getMapper(SpecialSQLMapper.class);
User user=new User(null,"小明","123",20,"男","[email protected]");
specialSQLMapper.insertUser(user);
System.out.println(user);//User{id=6, username='小明', password='123', age=20, email='[email protected]'}
}
useGeneratedKeys:表示当前添加功能使用了自增的主键 keyProperty:将添加的数据的自增主键为实体类类型的参数的属性赋值
自定义映射resultMap
resultMap处理字段和属性映射的关系
若字段名和实体类中的属性名不一致,则可以通过resultMap设置自定义映射
全局配置
<!--
字段名和属性名不一致,如何处理映射关系
1.为查询的字段设置别名,和属性名保持一致
2.当字段符合MySQL要求使用_,而属性符合java的要求使用驼峰,
此时可以在Mybatis核心配置文件中设置一个全局配置,可自动将下划线映射为驼峰
<setting name="mapUnderscoreToCamelCase" value="true"/>
-->
<!--Emp getEmpByEmpId(@Param("empId") Integer empId);-->
<select id="getEmpByEmpId" resultType="Emp">
<!--select emp_Id empId,emp_name empName,age,gender from t_emp where emp_id=#{empId}-->
select * from t_emp where emp_id=#{empId}
</select>
Emp getEmpByEmpId(@Param("empId") Integer empId);
自定义映射
<!--
resultMap:设置自定义的映射关系
id:唯一标识
type:处理映射关系的实体类的类型
常用的标签
id:处理主键和实体类中实现的映射关系
result:处理普通字段和实体类中的属性的映射关系
column:设置映射关系中的字段名,必须是sql查询出的某个字段
property:设置映射关系中属性的属性名,必须是处理的实体类类型中的属性名
association:处理多对一的映射关系(处理实体类类型的属性)
collection:处理一对多的映射关系(处理集合类型的属性)
-->
<resultMap id="empResultMap" type="Emp">
<id column="emp_id" property="empId"/>
<result column="emp_name" property="empName"/>
<result column="age" property="age"/>
<result column="gender" property="gender"/>
</resultMap>
<select id="getEmpByEmpId" resultMap="empResultMap">
select * from t_emp where emp_id=#{empId}
</select>
对一是对象:private Dept dept;
对多是集合
处理多对一的映射关系
public class Emp {
private Integer empId;
private String empName;
private Integer age;
private String gender;
private Dept dept;
}
-
级联方式处理
/**
* 获取员工及对应部门的信息
* @param empId
* @return
*/
Emp getEmpAndDeptByEmpId(@Param("empId")Integer empId);<resultMap id="empAndDeptResultMap" type="Emp">
<id column="emp_id" property="empId"/>
<result column="emp_name" property="empName"/>
<result column="age" property="age"/>
<result column="gender" property="gender"/>
<result column="dept_id" property="dept.deptId"/>
<result column="dept_name" property="dept.deptName"/>
</resultMap>
<!--getEmpAndDeptByEmpId-->
<select id="getEmpAndDeptByEmpId" resultMap="empAndDeptResultMap">
select t_emp.*,t_dept.*
from t_emp left join t_dept
on t_emp.dept_id=t_dept.dept_id
where t_emp.emp_id=#{empId}
</select> -
association
<resultMap id="empAndDeptResultMap" type="Emp">
<id column="emp_id" property="empId"/>
<result column="emp_name" property="empName"/>
<result column="age" property="age"/>
<result column="gender" property="gender"/>
<!--
association:处理多对一的映射关系(处理实体类类型的属性)
property:设置需要处理映射关系的属性的属性名
javaType:设置要处理的属性的类型
-->
<association property="dept" javaType="Dept">
<id column="dept_id" property="deptId"/>
<result column="dept_name" property="deptName"/>
</association>
</resultMap> -
分步查询
/**
* 通过分步查询获取员工及对应部门的信息的第一步
* @param empId
* @return
*/
Emp getEmpAndDeptByStepOne(@Param("empId")Integer empId);<resultMap id="empAndDeptByStepResultMap" type="Emp">
<id column="emp_id" property="empId"/>
<result column="emp_name" property="empName"/>
<result column="age" property="age"/>
<result column="gender" property="gender"/>
<!--
property:设置需要处理映射关系的属性的属性名
select:设置分步查询的sql的唯一标识
column:将当前sql语句查询出的某个字段作为分步查询的sql的条件
fetchType:在开启了延迟加载的环境中,通过该属性设置当前的分步查询是否使用延迟加载
eager(立即加载)|lazy(延迟加载)
-->
<association property="dept"
select="com.zwb.mapper.DeptMapper.getEmpAndDeptByStepTwo"
column="dept_id">
</association>
</resultMap>
<!--getEmpAndDeptByStepOne-->
<select id="getEmpAndDeptByStepOne" resultMap="empAndDeptByStepResultMap">
select * from t_emp where emp_id=#{empId}
</select>/**
* 通过分步查询获取员工及对应部门的信息的第二步
* @return
*/
Dept getEmpAndDeptByStepTwo(@Param("deptId")Integer deptId);<!--getEmpAndDeptByStepTwo-->
<select id="getEmpAndDeptByStepTwo" resultType="Dept">
select * from t_dept where dept_id=#{deptId}
</select>分步查询的优点:可以实现延迟加载
但需要在配置文件中开启全局配置
<!--开启延迟加载--> <setting name="lazyLoadingEnabled" value="true"/> <!--按需加载--> <setting name="aggressiveLazyLoding" value="false"/>
开启后,如果没有调用其他的表的字段,则不会执行其他sql语句
如System.out.println(emp.getAge());则不会执行dept的sql语句
处理一对多的映射关系
public class Dept {
private Integer deptId;
private String deptName;
private List<Emp> emps;
}
-
collection
/**
* 查询部门以及部门中对应的员工的信息
* @param deptId
* @return
*/
Dept getDeptAndEmp(@Param("deptId")Integer deptId);<resultMap id="deptAndEmpResultMap" type="Dept">
<id column="dept_id" property="deptId"/>
<result column="dept_name" property="deptName"/>
<!--
ofType:设置集合类型的属性中存储的数据的类型
-->
<collection property="emps" ofType="Emp">
<id column="emp_id" property="empId"/>
<result column="emp_name" property="empName"/>
<result column="age" property="age"/>
<result column="gender" property="gender"/>
</collection>
</resultMap>
<!--getDeptAndEmp-->
<select id="getDeptAndEmp" resultMap="deptAndEmpResultMap">
select *
from t_dept d LEFT JOIN t_emp e
ON d.dept_id=e.dept_id
WHERE d.dept_id=#{deptId}
</select> -
分步查询
/**
* 通过分步查询来查询部门以及部门中的员工的第一步
* @param deptId
* @return
*/
Dept getDeptAndEmpByStepOne(@Param("deptId")Integer deptId);<resultMap id="deptAndEmpResultMapByStep" type="Dept">
<id column="dept_id" property="deptId"/>
<result column="dept_name" property="deptName"/>
<collection property="emps"
select="com.zwb.mapper.EmpMapper.getDeptAndEmpByStepTwo"
column="dept_id"></collection>
</resultMap>
<!--getDeptAndEmpByStepOne-->
<select id="getDeptAndEmpByStepOne" resultMap="deptAndEmpResultMapByStep">
select * from t_dept where dept_id=#{deptId}
</select>/**
* 通过分步查询来查询部门以及部门中的员工的第二步
* @param deptId
* @return
*/
List<Emp> getDeptAndEmpByStepTwo(@Param("deptId")Integer deptId);<!--getDeptAndEmpByStepTwo-->
<select id="getDeptAndEmpByStepTwo" resultType="Emp">
select * from t_emp where dept_id=#{deptId}
</select>
小结
-
关联-association (多对一)
-
集合-collection(一对多)
-
javatType&ofType
-
javaType 用来指定实体类中属性的类型
-
ofType 用来指定映射到List或集合中的pojo类型,泛型中的约束类型
-
动态SQL
什么是动态SQL:动态SQL就是根据不同的条件生成不同的SQL语句
Where
where 元素只会在至少有一个子元素返回内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除,但内容后多余的AND无法去除。
If
通过test属性的表达式判断是否将标签中的内容拼接到sql语句中
<!--getEmpByCondition-->
<select id="getEmpByCondition" resultType="Emp">
select * from t_emp
<where>
<if test="empName != null and empName != ''">
emp_name=#{empName}
</if>
<if test="age != null and age != ''">
and age=#{age}
</if>
<if test="gender != null and gender != ''">
and gender=#{gender}
</if>
</where>
</select>
trim
<!--
trim
prefix、suffix:在标签中的内容前或后添加指定内容
prefixOverrides、suffixOverrides:在标签中的内容前或后去除指定内容
-->
<select id="getEmpByConditionTwo" resultType="Emp">
select * from t_emp
<trim prefix="where" suffixOverrides="and">
<if test="empName != null and empName != ''">
emp_name=#{empName} and
</if>
<if test="age != null and age != ''">
age=#{age} and
</if>
<if test="gender != null and gender != ''">
gender=#{gender} and
</if>
</trim>
</select>
choose
<!--
相当于if。。。else if。。。else
when至少设置一个,otherwise最多设置一个
-->
<!--getEmpByChoose-->
<select id="getEmpByConditionTwo" resultType="Emp">
select * from t_emp
<where>
<choose>
<when test="empName != null and empName != ''">
emp_name=#{empName}
</when>
<when test="age != null and age != ''">
age=#{age}
</when>
<when test="gender != null and gender != ''">
gender=#{gender}
</when>
<otherwise>
</otherwise>
</choose>
</where>
</select>
foreach
/**
* 批量添加员工信息
* @param emps
*/
void insertMoreEmp(@Param("emps") List<Emp> emps);
<!--insertMoreEmp-->
<insert id="insertMoreEmp">
insert into t_emp values
<foreach collection="emps" item="emp" separator=",">
(null,#{emp.empName},#{emp.age},#{emp.gender},null)
</foreach>
</insert>
/**
* 批量删除
* @param empIds
*/
void deleteMoreEmp(@Param("empIds") Integer[] empIds);
IN
<!--deleteMoreEmp-->
<delete id="deleteMoreEmp">
delete from t_emp where emp_id in
<foreach collection="empIds" item="empId" separator="," open="(" close=")">
#{empId}
</foreach>
</delete>
OR
<delete id="deleteMoreEmp">
<!--delete from t_emp where emp_id in-->
<!--<foreach collection="empIds" item="empId" separator="," open="(" close=")">-->
<!-- #{empId}-->
<!--</foreach>-->
delete from t_emp where
<foreach collection="empIds" item="empId" separator="or">
emp_id=#{empId}
</foreach>
</delete>
foreach collection:设置要循环的数组或集合 item:用一个字符串来表示数组或集合中的每一个数据 separator:设置每次循环的数据之间的分隔符 open:循环内容以什么开始 close:循环内容以什么结束
set
set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。set 元素会动态地在行首插入 set 关键字,并会删掉额外的逗号
<update id="UpdateBlog" parameterType="map">
update mybatis.blog
<set>
<if test="title!=null">
title=#{title},
</if>
<if test="author!=null">
author=#{author}
</if>
</set>
where id=#{id}
</update>
所谓的动态SQL,本质还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码
SQL片段
有的时候,我们可能会将一些功能部分抽取出来,方便复用
-
使用sql标签抽取公共部分
<sql id="if-title-author">
<if test="title!=null">
and title=#{title}
</if>
<if test="author!=null">
and author=#{author}
</if>
</sql> -
在需要使用的地方使用Include标签引用
<select id="queryBlogIf" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<include refid="if-title-author"></include>
</where>
</select>注意事项
-
最好基于单表来定义SQL片段
-
不要存在where标签
-
MyBatis的缓存
-
什么是缓存
-
存在内存中的临时数据
-
-
为什么使用缓存
-
减少和数据库的交互次数,减少系统开销,提高系统效率
-
-
什么样的数据能使用缓存
-
经常查询且不经常改变的数据
-
一级缓存
是SqlSession级别,通过一个SqlSession查询的数据会被缓存,下次查询相同数据时,就会从缓存中直接获取,不会从数据库重新访问
-
使一级缓存失效的的情况
-
不同的SqlSession对应不同的一级缓存
-
同一个SqlSeesion但查询条件不同
-
同一个SqlSession两次查询期间任意一次执行了任何一次增删改操作
-
同一个SqlSession两次查询期间手动清空了缓存
-
SqlSession sqlSession1= SqlSessionUtil.getSqlSession();
CacheMapper cacheMapper1=sqlSession1.getMapper(CacheMapper.class);
Emp emp=cacheMapper1.getEmpById(1);
System.out.println(emp);
//sqlSession1.clearCache();//清空SqlSession一级缓存
cacheMapper1.InsertEmp(new Emp(null,"小黑",25,"男"));
Emp emp2=cacheMapper1.getEmpById(1);
System.out.println(emp2);
SqlSession sqlSession2= SqlSessionUtil.getSqlSession();
CacheMapper cacheMapper2=sqlSession2.getMapper(CacheMapper.class);
Emp emp3=cacheMapper2.getEmpById(1);
System.out.println(emp3);
二级缓存
二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询结果会被缓存;此后再次执行相同的查询语句时,结果就会从缓存中获取
开启条件:
-
在核心配置文件中,设置全局属性cacheEnabled=“true”,默认为true,无需设置
-
在映射文件中设置标签<cache/>
-
二级缓存必须在SqlSession关闭或提交后有效(即一级缓存失效后)
-
查询的数据所转换的实体类型必须实现序列化的接口
//实现序列化接口
public class Emp implements Serializable
使二级缓存失效:
-
两次查询间执行了任意的增删改,会使一级和二级缓存同时失效
public void testCache() throws IOException {
InputStream is=Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession1=sessionFactory.openSession(true);
CacheMapper mapper1=sqlSession1.getMapper(CacheMapper.class);
Emp emp1=mapper1.getEmpById(2);
System.out.println(emp1);
sqlSession1.close();
SqlSession sqlSession2=sessionFactory.openSession(true);
CacheMapper mapper2=sqlSession2.getMapper(CacheMapper.class);
Emp emp2=mapper2.getEmpById(2);
System.out.println(emp2);
sqlSession2.close();
}
缓存查询顺序
先查询二级缓存,因为二级缓存中可能会有其他程序已经查出的数据,可以直接使用。
如二级缓存没有,再查询一级缓存,如一级缓存也没有,则查询数据库。
SqlSession关闭后,一级缓存的数据会写入二级缓存
MyBatis的逆向工程
正向:先创建Java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程的
逆向:先创建数据库表,由框架负责根据数据库表,反向生成如下资源
Java实体类
Mapper接口
Mapper映射文件
创建逆向工程的步骤
-
添加依赖和插件
<!--控制Maven在构建过程中相关配置-->
<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.13</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build> -
创建Mybatis核心配置文件
-
创建逆向工程的配置文件
文件名必须是:generatorConfig.xml
<?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>
<!-- 数据库驱动:选择你的本地硬盘上面的数据库驱动包 -->
<!--<classPathEntry location="D:\maven-warehouse\repository\mysql\mysql-connector-java\5.1.47\mysql-connector-java-5.1.47.jar"/>-->
<!-- <classPathEntry location="D:\maven-warehouse\repository\mysql\mysql-connector-java\8.0.17\mysql-connector-java-8.0.17.jar"/> -->
<!--
targetRuntime:执行生成的逆向工程的版本
MyBatis3:生成带条件的CRUD
MyBatis3Simple:生成基本的CRUD
-->
<context id="DB2Tables" targetRuntime="MyBatis3">
<!-- 数据库连接驱动类,URL,用户名、密码 -->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC"
userId="root"
password="123456">
</jdbcConnection>
<!--JavaBean的生成策略-->
<javaModelGenerator targetPackage="com.zwb.pojo" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- 生成xml映射文件:包名(targetPackage)、位置(targetProject) -->
<sqlMapGenerator targetPackage="com.zwb.mapper" targetProject=".\src\main\resources">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- 生成mapper接口:包名(targetPackage)、位置(targetProject) -->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.zwb.mapper" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!--
逆向分析表
tableName设置为*,可以对应所有表,此时不写domainObjectName
domainObjectName属性指定生成的实体类类名
-->
<table tableName="t_emp" domainObjectName="Emp"/>
<table tableName="t_dept" domainObjectName="Dept"/>
</context>
</generatorConfiguration> -
执行插件generate
使用
@Test
public void testMBG(){
SqlSession sqlSession= SqlSessionUtil.getSqlSession();
EmpMapper mapper=sqlSession.getMapper(EmpMapper.class);
//根据id查询数据
Emp emp=mapper.selectByPrimaryKey(1);
System.out.println(emp);
//查询所有数据
//List<Emp> list=mapper.selectByExample(null);
//根据条件查询数据
/*EmpExample example=new EmpExample();
example.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThan(20);
example.or().andGenderEqualTo("男");
List<Emp> list=mapper.selectByExample(example);
for (Emp emp1 : list) {
System.out.println(emp1);
}*/
emp=new Emp(1,"小黑子",null,"男");
//测试普通修改
//mapper.updateByPrimaryKey(emp);
//选择性修改
mapper.updateByPrimaryKeySelective(emp);
}
逆向工程只能对单表使用
分页插件
limit index,pageSize index:当前页的起始索引 index=(pageNum-1)*pageSize pageSize:每页显示的条数
count:总记录数 totalPage:总页数 totalPage=count/pageSize
if(count%pageSize!=0){ totalPage++; }
使用步骤
-
添加依赖
<!--分页插件依赖-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency> -
配置分页插件
在核心配置文件中配置插件
<plugins>
<!--设置分页插件-->
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
插件的使用
-
在查询功能前使用PageHelper.startPage(int pageNum,int pageSize)开启分页功能
pageNum:当前页页码
pageSize:每页显示的条数
@Test
public void testPage(){
SqlSession sqlSession= SqlSessionUtil.getSqlSession();
EmpMapper mapper=sqlSession.getMapper(EmpMapper.class);
//查询功能之前开启分页
Page<Object> page=PageHelper.startPage(1,4);
List<Emp> list=mapper.selectByExample(null);
//查询功能之后可以获取分页相关的所有数据
PageInfo<Emp> pageInfo=new PageInfo<>(list,5);
for (Emp emp : list) {
System.out.println(emp);
}
System.out.println(page);
System.out.println(pageInfo);
}
标签:mapper,映射,记录,查询,学习,sqlSession,emp,Mybatis,id From: https://www.cnblogs.com/H-MADAO/p/17124304.htmlpageNum:当前页的页码
pageSize:每页显示的条数
size:当前页显示的真实条数
total:总记录数
pages:总页数
prePage:上一页的页码
nextPage:下一页的页码
isFirstPage/ isLastPage:是否为最初/末页
hasPreviousPag/hasNextPage:是否存在上/下一页
navigatePages:导航分页的页码数
navigatepageNums:导航分页的页码[1, 2, 3, 4, 5]