IBatis的使用
1、IBatis是什么
回顾之前前端访问后端的整个流程:
View ------ >Controller --------> Service ---------> DAO ------> 数据库
View :前端jsp/HTML
Controller:Servlet/SpringMVC
Service :Spring
DAO:jdbc/dbutils/jdbctemplate/mybatis
mybatis实际上就是 DAO层的一个解决方案
jdbc、dbutils、jdbcTemplate、Hibernate以及mybatis的对比:
JDBC:代码非常复杂、速度快
Hibernate:代码精简、缺点(速度慢)
dbutils、jdbcTemplate:不是框架 只是对jdbc的一个简单的封装而已
mybatis:他是属于效率处于JDBC和Hibernate之间
他的代码的复杂度也是趋于 JDBC和Hibernate之间、 代码灵活
iBatis和mybatis之间的关系是什么?
ibatis是以前的叫法 mybatis是现在的叫法
2、iBatis能做什么
数据库的访问(CRUD)
整合缓存、还可以给类取别名、IBatis还提供了整合Spring的第三方的包
3、IBatis的简单的使用(一)(IBatis的数据不传参的问题)
3.1、导包
<!--导包-->
<!--下面就是iBatis的相关的包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--mysql的驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.10</version>
</dependency>
<!--日志门面-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.1</version>
</dependency>
<!-- 单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12-beta-3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
</dependencies>
3.2编写mybatis.xml配置文件
说明:配置文件的名字可以随意取
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--这个文件的作用:是对mybatis的全局配置-->
<configuration>
<!--
environments:环境+s,说明可以配置等多个环境
这里配置的环境是:数据库的连接信息
default:如果配置了多个环境 默认使用哪一个环境
-->
<environments default="mysql">
<!--配置一个环境:id:表示的是这个环境的名字
逻辑意义上是可以随便写的
-->
<environment id="mysql">
<!--配置的是事务的类型 ,默认配置JDBC就可以了 一般情况下使用的就是这个类型-->
<transactionManager type="JDBC"></transactionManager>
<!--这个配置的是数据源 这里你可以认为是固定写法-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///test"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
<!--这里是可以配置多个环境的 要使用哪一个环境那么就就配置上面的default就可以了 -->
<environment id="oracle">
<transactionManager type=""></transactionManager>
<dataSource type=""></dataSource>
</environment>
</environments>
<!--在全局配置文件中引入mapper.xml的配置文件-->
<!--不带参数-->
<mappers>
<mapper resource="UserMapper.xml"></mapper>
</mappers>
</configuration>
3.3、编写UserMapper.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">
<!--nameSpace:命名空间 这个命名空间和其他的命名空间不能重复 一般情况下 实体Mapper
逻辑上是可以随便写的 但是实际上要见名之意
-->
<mapper namespace="UserMapper">
<!--insert:标签:表示的是 添加数据到数据库
id:表示的是方法的名字
备注:标签之间 就是写SQL语句的地方
-->
<!--添加数据-->
<insert id="insert">
insert into t_user (username,password) values ('李四','12344');
</insert>
<!--修改数据-->
<update id="update">
update t_user set username='王五'
</update>
<!--查询数据-->
<!--resultType:表示返回数据的数据类型-->
<select id="select" resultType="com.szq.User">
select * from t_user where id=1
</select>
<!--删除数据-->
<delete id="delete">
delete from t_user where username='王五'
</delete>
</mapper>
3.3、编写测试代码(CRUD)
package com.szq;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.Reader;
public class Test001 {
/**
* 测试程序
*/
@Test
public void testA() throws IOException {
//1.找到mybatis.xml配置文件
Reader resourceAsReader = Resources.getResourceAsReader("mybatis.xml");
//2.创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsReader);
//通过工厂构建sqlSession对象
//sqlSession这个对象就是用来操作 数据库的对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//接下来就可以操作数据库了
//添加数据
// sqlSession.insert("UserMapper.insert");
//修改数据
// sqlSession.update("UserMapper.update");
//查询数据
// User o = sqlSession.selectOne("UserMapper.select");
// System.out.println(o);
//删除数据
sqlSession.delete("UserMapper.delete");
sqlSession.commit();//提交
sqlSession.close();//关闭
}
}
4、iBatis的基本的工具类的使用
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.Reader;
/**
* 帮助类
* mybatis帮助类
*/
public class MyBatisUtils {
//这个类是可以成为成员变量的(没有成员变量,不存在线程安全问题)
private SqlSessionFactory sqlSessionFactory=null;
//保存一个线程局部变量
private ThreadLocal<SqlSession> threadLocal;
{
try {
//需要加载资源
threadLocal = new ThreadLocal();
Reader resourceAsReader = Resources.getResourceAsReader("mybatis.xml");
sqlSessionFactory=new SqlSessionFactoryBuilder().build(resourceAsReader);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取操作数据库的对象
*
*/
public SqlSession getSqlSession(){
/**
* 编写访问数据库
* 1:在一个方法体里面 你调用任何多次数据库 我们只是要求 打开一次数据库 以及关闭一次就可以了
* 2;简单的说连接是可以重用的
*/
SqlSession sqlSession = threadLocal.get();
if(null!=sqlSession){//说明不是第一次访问数据库
return sqlSession;
}
//是第一次访问数据库
sqlSession = sqlSessionFactory.openSession();
//方法线程中去
threadLocal.set(sqlSession);
return sqlSession;
}
/**
* 关闭
*/
public void close(){
SqlSession sqlSession = threadLocal.get();
if(null!=sqlSession){
sqlSession.commit();
sqlSession.close();
//将线程中的局部变量置空
threadLocal.remove();
}
}
}
5、IBatis的简单使用(二)(IBatis的数据传参的问题)
5.1、传递简单参数问题
5.1.1、编写mybatis.xml配置文件
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--这个文件的作用:是对mybatis的全局配置-->
<configuration>
<!--
environments:环境+s,说明可以配置等多个环境
这里配置的环境是:数据库的连接信息
default:如果配置了多个环境 默认使用哪一个环境
-->
<environments default="mysql">
<!--配置一个环境:id:表示的是这个环境的名字
逻辑意义上是可以随便写的
-->
<environment id="mysql">
<!--配置的是事务的类型 ,默认配置JDBC就可以了 一般情况下使用的就是这个类型-->
<transactionManager type="JDBC"></transactionManager>
<!--这个配置的是数据源 这里你可以认为是固定写法-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///test"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
<!--这里是可以配置多个环境的 要使用哪一个环境那么就就配置上面的default就可以了 -->
<environment id="oracle">
<transactionManager type=""></transactionManager>
<dataSource type=""></dataSource>
</environment>
</environments>
<!--在全局配置文件中引入mapper.xml的配置文件-->
<!--带参数-->
<mappers>
<mapper resource="UserMapper1.xml"></mapper>
</mappers>
</configuration>
5.1.2、编写UserMapper1.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">
<!--nameSpace:命名空间 这个命名空间和其他的命名空间不能重复 一般情况下 实体Mapper
逻辑上是可以随便写的 但是实际上要见名之意
-->
<mapper namespace="UserMapper">
<!--传递简单参数 通过id更新数据
parameterType:表示的是传进去的参数的数据类型
这个数据类型有两种写法
1:写Java中数据类型的全路径 java.lang.String java.lang.Integer
2:使用mybatis中的数据类型 这个数据类型与 java中的数据类型是一一对应的
之前的占位符?在这里写成:#{写对应的key的名字}
简单的数据类型 一个字符串 一个int 一个float 没有key 那么这个时候 这个key
可以随便写 但是为了见名之意 一般写成value
-->
<insert id="insert" parameterType="map">
insert into t_user(username,password) values (#{username},#{password});
</insert>
<update id="update" parameterType="string">
update t_user set username='王五' where username=#{username};
</update>
<select id="select" parameterType="int" resultType="com.szq.User">
select * from t_user where id=#{value};
</select>
<delete id="delete" parameterType="int">
delete from t_user where id=#{id}
</delete>
</mapper>
5.1.3、编写测试代码(CRUD)
package com.szq.parameter;
import com.szq.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.HashMap;
public class Test002 {
/**
* 测试带参数
*/
@Test
public void testUpdate(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
sqlSession.update("UserMapper.update","张三");
myBatisUtils.close();
}
@Test
public void testSelect(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
Object o = sqlSession.selectOne("UserMapper.select", 2);
System.out.println(o);
myBatisUtils.close();
}
@Test
public void testDelete(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
sqlSession.delete("UserMapper.delete",2);
myBatisUtils.close();
}
}
5.2、传递map集合
5.2.1 、编写xml配置文件
<insert id="insert" parameterType="map">
insert into t_user(username,password) values (#{username},#{password});
</insert>
5.2.2、编写测试代码
@Test
public void testInsert(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.put("username","张三");
objectObjectHashMap.put("password","2222");
sqlSession.insert("UserMapper.insert",objectObjectHashMap);
myBatisUtils.close();
}
5.3 、传递数组
5.3.1 、编写xml配置文件
<!--传递数组-->
<!--动态sql传递数组的问题
通过一连串的id 找用户对象
select * from t_user where id in (6,7,8)
<if>标签用来做条件判断
如果前端传递的是数组类型的数据 那么 这里使用 list来接收
遍历数据的时候 那么还是使用 array来做遍历
collection:表示的是要遍历的这个集合或者数组
open:sql语句的构成 以什么开始
close:SQL语句的构成以什么结束
separator:遍历出来的数据之间使用什么进行分割
item:每一次遍历出来的数据的名字
注意:每一次遍历出来的数据 要使用 #{遍历的名字} 去进行获取
-->
<select id="findUserById" resultType="com.szq.User" parameterType="list">
select * from t_user
<if test="array!=null">
where id in
<foreach collection="array" open="(" close=")" separator="," item="id">
#{id}
</foreach>
</if>
</select>
5.3.2、编写测试代码
/**
* 传递数组
*/
@Test
public void testFindUserById(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
int arr[]={4,5,6};
List<User> users = sqlSession.selectList("UserMapper.findUserById", arr);
System.out.println(users);
myBatisUtils.close();
}
5.4、传递集合
5.4.1、编写xml配置文件
<!--传递集合-->
<select id="findUserById2" resultType="com.szq.User" parameterType="list">
select * from t_user
<if test="list !=null">
where id
<foreach collection="list" open="in (" close=")" separator="," item="id">
#{id}
</foreach>
</if>
</select>
5.4.2、 编写测试代码
/**
* 传递集合
*/
@Test
public void testFindUserById2(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
ArrayList<Object> objects = new ArrayList<>();
objects.add(4);
objects.add(6);
List<User> users = sqlSession.selectList("UserMapper.findUserById2", objects);
System.out.println(users);
myBatisUtils.close();
}
5.5、传递自定义的类的对象
5.5.1、编写xml文件
<!--通过用户名和密码找到用户对象
表示的是传递的是 用户对象
-->
<!--传递自定义数据类型User-->
<select id="select1" parameterType="com.szq.User" resultType="com.szq.User">
select * from t_user t where t.username=#{username} and t.password=#{password};
</select>
5.5.2、编写测试代码
public void testSelect(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
// User user = new User(1,"张三","123");
User user=new User();
user.setUsername("张三");
user.setPassword("123");
User o = sqlSession.selectOne("UserMapper.select1",user);
System.out.println(o);
myBatisUtils.close();
}
说明:不能一次性传递多个简单的参数
因为后端在接受数据的时候 采用的key是随机的 也就说 可以随便写的 假设你传递了多个简单的参数 那么后端无法区分 这个值是哪一个的
没有办法进行传递 ------ 如果要进行传递 那么你就封装成 map集合 或者 java的类
6、动态SQL的问题
什么是动态SQL? 在进行查询的时候 会根据前端传递数据的条件 来动态的进行SQL语句的拼接的这种方法 就称为动态SQL
需求:前端随地的给定一串id 要求的是 这一串的id的用户信息全部查询出来 这一串id可以是任意的
id:1,2,3,4 或者3,2,4,5
select * from t_user where id in(不确定)
动态sql解决的问题
6.1、传递数组
<!--传递数组-->
<!--动态sql传递数组的问题
通过一连串的id 找用户对象
select * from t_user where id in (6,7,8)
<if>标签用来做条件判断
如果前端传递的是数组类型的数据 那么 这里使用 list来接收
遍历数据的时候 那么还是使用 array来做遍历
collection:表示的是要遍历的这个集合或者数组
open:sql语句的构成 以什么开始
close:SQL语句的构成以什么结束
separator:遍历出来的数据之间使用什么进行分割
item:每一次遍历出来的数据的名字
注意:每一次遍历出来的数据 要使用 #{遍历的名字} 去进行获取
-->
<select id="findUserById" resultType="com.szq.User" parameterType="list">
select * from t_user
<if test="array!=null">
where id in
<foreach collection="array" open="(" close=")" separator="," item="id">
#{id}
</foreach>
</if>
</select>
6.2、传递集合
<!--传递集合-->
<select id="findUserById2" resultType="com.szq.User" parameterType="list">
select * from t_user
<if test="list !=null">
where id
<foreach collection="list" open="in (" close=")" separator="," item="id">
#{id}
</foreach>
</if>
</select>
6.3、更新数据
<!--插入数据
prefix:前缀 拼接的前缀
suffix:拼接的后缀
suffixOverrides:这个是去掉结束位置的某一个符号 可以是任意的
prefixOverrides:去掉开始的符号 这个符号是任意的
-->
<insert id="insert222" parameterType="com.szq.User">
insert into t_user
<trim prefix="(" suffix=")" suffixOverrides="," prefixOverrides="">
<if test="userName != null">
userName,
</if>
<if test="password !=null">
password
</if>
</trim>
<trim prefix="values(" suffix=")" suffixOverrides=",">
<if test="userName != null">
#{userName},
</if>
<if test="password !=null">
#{password}
</if>
</trim>
</insert>
6.4、动态sql和sql片段
<select id="findUserByCondition" parameterType="com.qf.cd.helloworld.User" resultType="com.qf.cd.helloworld.User">
select * from t_user where 1=1
<if test="userName != null">
and userName=#{userName}
</if>
<if test="password !=null">
and password=#{password}
</if>
</select>
<select id="findUserByCondition1" parameterType="com.szq.User" resultType="com.szq.User">
select * from t_user
<include refid="aa"></include>
</select>
<!--抽取sql标签
抽取的sql在任何地方都可以进行调用
-->
<sql id="aa">
<where>
<if test="userName != null">
and userName=#{userName}
</if>
<if test="password !=null">
and password=#{password}
</if>
</where>
</sql>
7、iBatis的结果集的返回问题
7.1、返回简单数据
<!--返回简单参数
需求:通过用户名 查询用户id
-->
<select id="findIdByUserName" parameterType="string" resultType="int">
select id from t_user where userName=#{value}
</select>
@Test
public void testFindIdByUsername(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
Object id = sqlSession.selectOne("UserMapper.findIdByUserName", "张三");
System.out.println(id);
myBatisUtils.close();
}
7.2、返回自定义的类的对象
<!--返回简单参数
需求:通过id 查询用户对象
-->
<select id="findUserById" parameterType="int" resultType="com.szq.User">
select * from t_user where id=#{value}
</select>
@Test
public void testFindUserByUsername(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
Object user = sqlSession.selectOne("UserMapper.findUserById", 6);
System.out.println(user);
myBatisUtils.close();
}
7.3、返回list集合 但是集合中是常见的数据类型
<!--返回list集合 但是集合中是常见的数据类型-->
<!-- 需求:通过一连串的id 查询一连串的名字-->
<!-- 如果返回集合的数据类型 那么下面的结果集的返回只用写 集合中泛型的数据类型就OK了-->
<select id="select2" parameterType="string" resultType="string">
select username from t_user where id in(4,5,6);
</select>
/**
* 返回list集合 但是集合中是常见的数据类型
*/
@Test
public void testFindUserById(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
List<String> str = sqlSession.selectList("UserMapper.select2");
System.out.println(str);
myBatisUtils.close();
}
7.4、返回一个集合 集合中的泛型是自定义的类的类型
<!--返回一个集合 集合中的泛型是自定义的类的类型-->
<select id="select3" resultType="com.szq.User">
select * from t_user ;
</select>
/**
* 返回集合,集合是自定义数据类型
*/
@Test
public void testFindAllUser(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
List<User> users = sqlSession.selectList("UserMapper.select3");
System.out.println(users);
myBatisUtils.close();
}
8、数据库的字段和实体不对应问题
8.1、解决问题之取别名
<!--数据库的字段和实体不对应-->
<!--解决方法1:使用别名-->
<select id="findUserAll" resultType="com.szq.parameter1.User">
<!--数据库字段 as 实体类字段-->
select id as userId,username as user_Name,password as pass_Word from t_user;
</select>
/**
* 通过别名的方式
*/
@Test
public void testFindUserById(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
List<User> o = sqlSession.selectList("UserMapper.findUserAll");
System.out.println(o);
myBatisUtils.close();
}
8.2、通过结果集映射解决问题
<!--通过结果集映射解决这个问题-->
<!--配置结果集映射关系-->
<!--type:是结果集返回的类型-->
<resultMap id="findUserAll2ResultMap" type="com.szq.parameter1.User">
<!--配置主键映射-->
<!--property:写实体的字段 column:写数据库的字段-->
<id property="userId" column="id"></id>
<!--配置普通字段映射-->
<result property="user_Name" column="username"></result>
<result property="pass_Word" column="password"></result>
<result property="age" column="age"></result>
</resultMap>
<select id="findUserAll2" resultType="com.szq.parameter1.User" resultMap="findUserAll2ResultMap">
select * from t_user;
</select>
/**
* 配置结果集映射
*/
@Test
public void testFindUserById2(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
List<User> o = sqlSession.selectList("UserMapper.findUserAll2");
System.out.println(o);
myBatisUtils.close();
}
9、一对一映射关系
需求:一个用户拥有一个身份证、一个身份证唯一的对应了一个用户
用户与身份证–>是一对一的关系 在查询 用户的时候 ,希望的是能查询出身份证
9.1、用户实体
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String username;
private String password;
private Integer age;
//维护
private IdCard idCard;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class IdCard {
private int id;
private String idNum;
private int userId;
}
9.2 、编写方法的配置
<?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
逻辑上是可以随便写的 但是实际上要见名之意
-->
<mapper namespace="UserMapper">
<!--一对一映射关系-->
<!--查询到所有的用户以及各自的身份证号码-->
<!--配置结果集映射-->
<resultMap id="findUserAllResultMap" type="com.szq.oneToone.User">
<!--配置主键-->
<id property="id" column="id"></id>
<!--配置普通字段的映射-->
<result property="username" column="username"></result>
<result property="password" column="password"></result>
<result property="age" column="age"></result>
<!--接下来配置一对一的映射关系
property:这个实际上就是 java实体中 对象关系的名字
javaType:数据类型(全限定名)
column:这个是为了将上面的某一个列的内容给映射下来
相当于 调用方法的时候要传值
select:相当于要调用另外的mapper来实现整个逻辑
-->
<association property="idCard" javaType="com.szq.oneToone.IdCard">
<!--配置主键映射关系-->
<id property="id" column="cardid"></id>
<result property="idNum" column="idNum"></result>
<result property="userId" column="userId"></result>
</association>
</resultMap>
<select id="findUserAll" resultMap="findUserAllResultMap">
select * from t_user t1,t_idcard t2 where t1.id=t2.userId
</select>
9.3、测试
/**
* 一对一映射关系
*/
public class Test001 {
@Test
public void testOneToOne(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
List<User> o = sqlSession.selectList("UserMapper.findUserAll");
System.out.println(o);
myBatisUtils.close();
}
}
10、一对多映射关系
一个部门有多名员工,在查询部门时需求查出部门下的员工
10.1、部门以及员工实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dept {
private int id;
private String deptName;
private String deptDes;
private List<Emp> empList;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp {
private int id;
private String empName;
private int gender;
}
10.2、编写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">
<!--nameSpace:命名空间 这个命名空间和其他的命名空间不能重复 一般情况下 实体Mapper
逻辑上是可以随便写的 但是实际上要见名之意
-->
<mapper namespace="DeptMapper">
<!--一对多映射关系-->
<!--获取所有的部门,并且要获取一个部门下面的员工-->
<resultMap id="findDeptResultMap" type="com.szq.oneToMore.Dept">
<!--主键映射-->
<id property="id" column="id"></id>
<!--配置普通字段映射-->
<result property="deptName" column="deptName"></result>
<result property="deptDes" column="deptDes"></result>
<!--一对多-->
<collection property="empList" ofType="com.szq.oneToMore.Emp">
<id property="id" column="empid"></id>
<result property="empName" column="empName"></result>
<result property="gender" column="gender"></result>
</collection>
</resultMap>
<select id="findDept" resultMap="findDeptResultMap">
select * from t_dept t1,t_emp t2 where t2.deptid=t1.id;
</select>
10.3、测试
/**
* 一对多映射关系
*/
public class Test001 {
@Test
public void testOneToMore(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
List<Dept> o = sqlSession.selectList("DeptMapper.findDept");
System.out.println(o);
myBatisUtils.close();
}
}
11、取别名的问题
为什么要整个别名? 因为我们很多时候在写 这个java类型的时候 都写的的全路径
简单的说就是为了解决 传入参数的类型过长 以及 返回参数的类型 过长的问题
mybatis.xml中进行配置
<!--取别名-->
<typeAliases>
<!--
type:是要取别名的这个java类型
alias:这个是别名的名字
别名一般情况下是取给java实体类的 po dto
-->
<!-- <typeAlias type="com.szq.one2many.Dept" alias="deptbobo"></typeAlias>
<typeAlias type="com.szq.one2many.Employee" alias="empbobo"></typeAlias>-->
<!--这个就表示的是给这个包里所有的类都取别名
默认的别名的名字是 类名的首写字母小写
-->
<package name="com.szq.one2many"></package>
</typeAliases>
12、懒加载的问题
12.1、关闭积极的加载、开启懒加载
<!--iBatis本身的设置 -->
<!--mybatis.xml里面设置:注意放置顺序-->
<settings>
<!--是否使能延迟的加载 -->
<setting name="lazyLoadingEnabled" value="true" />
<!--关闭那个积极的加载 -->
<setting name="aggressiveLazyLoading" value="false" />
</settings>
12.2、xml配置问题
<!--mybatis.xml里面的mappers配置如下-->
<mappers>
<mapper resource="UserMapper4.xml"></mapper>
<!--懒加载配置如下-->
<mapper resource="IdCardMapper.xml"></mapper>
</mappers>
<?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
逻辑上是可以随便写的 但是实际上要见名之意
-->
<mapper namespace="UserMapper">
<!--一对一映射关系-->
<!--查询到所有的用户以及各自的身份证号码-->
<!--配置结果集映射-->
<resultMap id="findUserAllResultMap" type="com.szq.oneToone.User">
<!--配置主键-->
<id property="id" column="id"></id>
<!--配置普通字段的映射-->
<result property="username" column="username"></result>
<result property="password" column="password"></result>
<result property="age" column="age"></result>
<!--接下来配置一对一的映射关系
property:这个实际上就是 java实体中 对象关系的名字
javaType:数据类型(全限定名)
column:这个是为了将上面的某一个列的内容给映射下来
相当于 调用方法的时候要传值
select:相当于要调用另外的mapper来实现整个逻辑
-->
<!--懒加载-->
<association property="idCard" column="id" javaType="com.szq.oneToone.IdCard" select="IdCardMapper.findIdCard" fetchType="lazy">
</association>
</resultMap>
<select id="findUserAll" resultMap="findUserAllResultMap">
select * from t_user where id=4;
</select>
</mapper>
12.3、测试代码
/**
* 测试懒加载
*/
public class Test002 {
@Test
public void test(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
List<Object> objects = sqlSession.selectList("UserMapper.findUserAll");
// System.out.println(objects);
myBatisUtils.close();
}
}
13、二级缓存的问题
缓存:简单的说就是将查询出来的数据 放到一个地方,下一次查询相同的数据的时候不用去查询数据库
直接从缓存里面取数据,这样能够减轻SQL数据库的压力。
13.1、一级缓存
一级缓存又叫做session缓存。整个缓存的生命周期由session来进行管理 ,session死了,那么缓存也没有了。
也就是说 一级缓存 实际上存在的范围是 sqlsession的创建完成到sqlsession的关闭之前。
@Test
public void test1(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
User users=sqlSession.selectOne("UserMapper.findUserAll");
User users1=sqlSession.selectOne("UserMapper.findUserAll");
User users3=sqlSession.selectOne("UserMapper.findUserAll");
User users4=sqlSession.selectOne("UserMapper.findUserAll");
User users5=sqlSession.selectOne("UserMapper.findUserAll");
User users6=sqlSession.selectOne("UserMapper.findUserAll");
User users7=sqlSession.selectOne("UserMapper.findUserAll");
//清空一级缓存
sqlSession.clearCache();
sqlSession.commit();
sqlSession.close();
}
查询相同的数据,也就是说sql语句相同,在sqlsession的创建完成到sqlsession的关闭之前,相同的sql语句只会执行一次----一级缓存。一级缓存是不能跨session的 ,现实开发中并没有什么用 ,而且这个缓存的维护 ,也并不需要我们人为的去完成,缓存的使能和销毁都是由session自身去完成的
13.2、二级缓存
二级缓存解决了一级缓存的缺点,它能够session进行使用 ,在开发中 一般我们使用的都是二级缓存。
开启二级缓存
<!--开启二级缓存-->
<setting name="cacheEnabled" value="true"></setting>
导入mybatis的ehcache的支持包
github上下载:https://github.com/mybatis/ehcache-cache/releases
在resource目录下配置ehcache.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<ehcache
updateCheck="false">
<!-- 缓存写入文件目录 不需要你引入的 只是配置好就可以 他会默认来找当前的这个位置-->
<diskStore path="d:\\mytemp"/>
<!-- 数据过期策略 -->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
</ehcache>
在需要缓存内容的mapper上 使用cache标签
<!--二级缓存的地方-->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
* 测试二级缓存
*/
@Test
public void test2(){
MyBatisUtils myBatisUtils = new MyBatisUtils();
SqlSession sqlSession = myBatisUtils.getSqlSession();
List<Object> objects1 = sqlSession.selectList("UserMapper.findUserAll");
myBatisUtils.close();
MyBatisUtils myBatisUtils1 = new MyBatisUtils();
SqlSession sqlSession1= myBatisUtils1.getSqlSession();
List<Object> objects2 = sqlSession1.selectList("UserMapper.findUserAll");
myBatisUtils1.close();
MyBatisUtils myBatisUtils2 = new MyBatisUtils();
SqlSession sqlSession2 = myBatisUtils2.getSqlSession();
List<Object> objects3 = sqlSession2.selectList("UserMapper.findUserAll");
myBatisUtils2.close();
}
**测试结果**
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200625204852339.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NzA4NDg1Nw==,size_16,color_FFFFFF,t_70#pic_center)