延迟加载策略
延迟加载的简介:什么是延迟加载,为什么要使用延迟加载
1.什么是延迟加载?
延迟加载(lazy load)是(也称为懒加载)关联关系对象默认的加载方式,延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作。
延迟加载,可以简单理解为,只有在使用的时候,才会发出sql语句进行查询。
2.为什么要使用延迟加载?
减少访问数据库的频率,我们要访问的数据量过大时,明显用缓存不太合适,因为内存容量有限为了减少并发量,减少系统资源的消耗。
配置延迟加载策略,并测试结果
在mybatis中使用resultMap来实现一对一,一对多,多对多关系的操作。主要是通过 association、collection 实现一对一及一对多映射。association、collection 具备延迟加载功能。
局部延时加载
DepartmentDao.xml配置文件
<select id="getDepartmentById" resultMap="DepartemntResultMap">
select * from department where d_id=#{id}
</select>
<resultMap id="DepartemntResultMap" type="Department">
<id column="d_id" property="id"></id>
<result column="d_name" property="name"></result>
<collection property="emps" ofType="Employee" column="d_id"
select="cn.offcn.mapper.EmployeeMapper.getEmployeeByDepartId"
fetchType=”lazy”>
</collection>
</resultMap>
相关联的查询标签上加 fetchType=”lazy”
fetchType默认值为eager 立即加载,Lazy为延时加载。
测试类
@Test
public void testGetDepartentById() throws Exception{
//获取SqlSession对象
SqlSession session = MyBatisUtils.getSession();
//调用SqlSession 创建 UserDao接口的代理对象
DepartmentDao departmentDao = session.getMapper(DepartmentDao.class);
Department dept=departmentDao.getDepartentById(1);
//打印
System.out.println(dept.getName);
//提交事务
session.commit();
//关闭连接
MyBatisUtils.close(session);
}
2.全局延时加载
如果希望所有关联都需要延时加载,可以在mybatis的核心配置文件中进行配置,不用在collection或association中指定。默认全局开启。
<settings>
<!--开启延时加载开关-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--关闭立即加载,实施按需加载-->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
MyBatis的逆向工程
逆向工程绍
MyBatis的一个主要的特点就是需要程序员自己编写sql,那么如果表太多的话,难免会很麻烦,所以mybatis官方提供了一个逆向工程,可以针对单表自动生成mybatis执行所需要的代码(包括mapper.xml、mapper.java、po..)。一般在开发中,常用的逆向工程方式是通过数据库的表生成代码。
构建项目环境
构建maven工程并导入依赖
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.7</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</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>
<properties resource="db.properties"></properties>
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<!--开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>
<typeAliases>
<package name="cn.offcn.entity"></package>
</typeAliases>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<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>
<package name="cn.offcn.mapper"></package>
</mappers>
</configuration>
编写逆向工程的配置文件generator.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>
<context id="testTables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis828_002"
userId="root" password="root">
</jdbcConnection>
<!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和
NUMERIC 类型解析为java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- targetProject:生成实体类的位置 -->
<javaModelGenerator targetPackage="cn.offcn.entity"
targetProject=".\src\main\java">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
<!-- 从数据库返回的值被清理前后的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- targetProject:mapper映射文件生成的位置 -->
<sqlMapGenerator targetPackage="cn.offcn.mapper"
targetProject=".\src\main\java">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage:mapper接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="cn.offcn.mapper"
targetProject=".\src\main\java">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 指定数据库表 -->
<table tableName="department"></table>
<table tableName="employee"></table>
<table tableName="person"></table>
<table tableName="idcard"></table>
<table tableName="student"></table>
<table tableName="teacher_student"></table>
<table tableName="teacher"></table>
</context>
</generatorConfiguration>
调用官方api实现逆向工程
package cn.test;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class GeneratorTest {
public static void main(String[] args) throws Exception{
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
//指定 逆向工程配置文件
File configFile = new File("F:\\828class\\workspace\\mybatis\\mybatis004_reflect\\generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callba
ck = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
callback, warnings);
myBatisGenerator.generate(null);
}
}
逆向工程自动生成的文件解析
使用逆向工程完成数据CRUD
//添加员工
public static void addEmployee(){
SqlSession session = MyBatisUtils.getSession();
EmployeeMapper employeeMapper=session.getMapper(EmployeeMapper.class);
Employee employee=new Employee();
employee.seteName("马大力");
employee.seteGender("男");
employee.seteAge(23);
employee.seteDepartId(1);
employeeMapper.insert(employee);
session.commit();
MyBatisUtils.close(session);
}
//根据id查询员工
public static void queryEmployeeById(){
SqlSession session = MyBatisUtils.getSession();
EmployeeMapper employeeMapper=session.getMapper(EmployeeMapper.class);
Employee emp=employeeMapper.selectByPrimaryKey(2);
System.out.println(emp);
session.commit();
MyBatisUtils.close(session);
}
//根据年龄查询员工
public static void queryEmployeeByAge(){
SqlSession session = MyBatisUtils.getSession();
EmployeeMapper employeeMapper=session.getMapper(EmployeeMapper.class);
EmployeeExample employeeExample=new EmployeeExample();
EmployeeExample.Criteria criteria=employeeExample.createCriteria();
criteria.andEAgeGreaterThan(20);
List<Employee> employeeList=employeeMapper.selectByExample(employeeExample);
for (Employee employee : employeeList) {
System.out.println(employee);
}
session.commit();
MyBatisUtils.close(session);
}
//根据年龄和性别查询员工
public static void queryEmployeeByAgeAndGender(){
SqlSession session = MyBatisUtils.getSession();
EmployeeMapper employeeMapper=session.getMapper(EmployeeMapper.class);
EmployeeExample employeeExample=new EmployeeExample();
EmployeeExample.Criteria criteria=employeeExample.createCriteria();
criteria.andEAgeGreaterThan(20);
criteria.andEGenderEqualTo("男");
List<Employee> employeeList=employeeMapper.selectByExample(employeeExample);
for (Employee employee : employeeList) {
System.out.println(employee);
}
session.commit();
MyBatisUtils.close(session);
}
//根据id修改员工
public static void updateEmployeeById(){
SqlSession session = MyBatisUtils.getSession();
EmployeeMapper employeeMapper=session.getMapper(EmployeeMapper.class);
Employee employee= employeeMapper.selectByPrimaryKey(1);
employee.seteGender("女");
employee.seteDepartId(2);
employeeMapper.updateByPrimaryKey(employee);
session.commit();
MyBatisUtils.close(session);
}
//根据id删除员工
public static void deleteEmployeeById(){
SqlSession session = MyBatisUtils.getSession();
EmployeeMapper employeeMapper=session.getMapper(EmployeeMapper.class);
employeeMapper.deleteByPrimaryKey(10);
session.commit();
MyBatisUtils.close(session);
}
//根据姓名更新员工
public static void updateEmployeeByName(){
SqlSession session = MyBatisUtils.getSession();
EmployeeMapper employeeMapper=session.getMapper(EmployeeMapper.class);
Employee employee= employeeMapper.selectByPrimaryKey(1);
employee.seteGender("男");
employee.seteAge(24);
EmployeeExample employeeExample=new EmployeeExample();
EmployeeExample.Criteria criteria = employeeExample.createCriteria();
criteria.andENameEqualTo(employee.geteName());
employeeMapper.updateByExample(employee,employeeExample);
session.commit();
MyBatisUtils.close(session);
}
//分页查询员工
public static void queryEmployees(int currentPage,int pageSize){
PageHelper.startPage(currentPage,pageSize);
SqlSession session = MyBatisUtils.getSession();
EmployeeMapper employeeMapper=session.getMapper(EmployeeMapper.class);
EmployeeExample employeeExample=new EmployeeExample();
List<Employee> employeeList=employeeMapper.selectByExample(employeeExample);
PageInfo<Employee> pageInfo=new PageInfo<>(employeeList);
List<Employee> empList=pageInfo.getList(); //取当前页的所有记录
long totalRecored=pageInfo.getTotal();//总记录数
int totalPages=pageInfo.getPages(); //总页数
System.out.println("总记录数:"+totalRecored);
System.out.println("总页数:"+totalPages);
for (Employee employee : empList) {
System.out.println(employee);
}
session.commit();
MyBatisUtils.close(session);
}
//根据性别和部门查询员工
public static void queryEmployeeByGenderNum(){
SqlSession session = MyBatisUtils.getSession();
EmployeeMapper employeeMapper=session.getMapper(EmployeeMapper.class);
EmployeeExample employeeExample=new EmployeeExample();
EmployeeExample.Criteria criteria = employeeExample.createCriteria();
criteria.andEGenderEqualTo("男");
criteria.andEDepartIdEqualTo(1);
long count= employeeMapper.countByExample(employeeExample);
System.out.println(count);
session.commit();
MyBatisUtils.close(session);
}
//根据部门查询员工
public static Employee queryEmployeeDepartmentById(int eid){
SqlSession session = MyBatisUtils.getSession();
EmployeeMapper employeeMapper=session.getMapper(EmployeeMapper.class);
Employee employee=employeeMapper.selectByPrimaryKey(eid);
//查部门
DepartmentMapper departmentMapper=session.getMapper(DepartmentMapper.class);
Department department=departmentMapper.selectByPrimaryKey(employee.geteDepartId());
employee.setDepart(department);
session.commit();
MyBatisUtils.close(session);
return employee;
}
public static void main(String[] args) {
addEmployee();
queryEmployeeById();
queryEmployeeByAge();
queryEmployeeByAgeAndGender();
updateEmployeeById();
updateEmployeeByName();
deleteEmployeeById();
queryEmployees();
queryEmployeeByGenderNum();
Employee employee=queryEmployeeDepartmentById(1);
System.out.println(employee.geteName()+"\t"
+employee.getDepart().getdName());
queryEmployees(1,2);
}
Mybatis 缓存
缓存简介
缓存是存在于内存中的临时数据,使用缓存的目的是减少和数据库的交互次数,提高执行效率。像大多数的持久化框架一样,Mybatis 也提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提高性能,Mybatis 中缓存分为一级缓存,二级缓存。
一级缓存
一级缓存介绍
mybatis一级缓存一种是SESSION级别的,针对同一个会话SqlSession中,执行多次条件完全相同的同一个sql,那么会共享这一缓存。
一级缓存结构图
编写用户持久层 Dao 接口
public interface EmployeeDao {
public Employee getEmployeeById(int id);
}
编写用户持久层映射文件
<select id="getEmployeeById" resultMap="EmployeeResultMap">
SELECT * FROM employee WHERE e_id=#{id}
</select>
<resultMap id="EmployeeResultMap" type="Employee">
<id column="e_id" property="id"></id>
<result column="e_name" property="name"></result>
<result column="e_gender" property="gender"></result>
<result column="e_age" property="age"></result>
</resultMap>
编写测试方法
public static void firstCahce(){
SqlSession session = MyBatisUtils.getSession();
EmployeeMapper employeeMapper=session.getMapper(EmployeeMapper.class);
//第一次查询
Employee employee1=employeeMapper.getEmployeeById(1);
System.out.println(employee1.getName());
//第二次查询
Employee employee2=employeeMapper.getEmployeeById(1);
System.out.println(employee2.getName());
MyBatisUtils.close(session);
}
一级缓存的分析
从上面的代码可以出,我们写了两次查询操作,但在访问数据时,只有一次。第一次先从一级缓存中获取,因为session是新创建的,一级缓存中没有数据,于是就查询数据获取数据,然后把查询的数据放到一级缓存中,此时一定要注意的是,一级缓存是一个Map集合,map的key是你的查询条件字符串,值就是查询出来的对象。等第二次查询时,先从一缓存中获取,因为上一次查询后已经放到一级缓存中了,所以从一级缓存中获取到了,就不用访问数据库了,减少和数据次的一次交互,提高了执行效率。
测试一级缓存的清空
当我们在两次查询之间做增、删、改操作都会把一级缓存清空,因为不清空就不能保证缓存中的数据与数据库中数据的一致性,可能会读取不正确的数据。
public static void firstCahce(){
SqlSession session = MyBatisUtils.getSession();
EmployeeMapper employeeMapper=session.getMapper(EmployeeMapper.class);
//第一次查询
Employee employee1=employeeMapper.getEmployeeById(1);
System.out.println(employee1.getName());
//新增员工
employeeMapper.addEmployee(new Employee("张小志","男",18));
//第二次查询
Employee employee2=employeeMapper.getEmployeeById(1);
System.out.println(employee2.getName());
MyBatisUtils.close(session);
}
二级缓存
二级缓存简介
二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个 SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。
二级缓存结构图
二级缓存的开启与关闭
在SqlMapConfig.xml 文件开启二级缓存
<settings>
<!-- 开启二级缓存的支持 -->
<setting name="cacheEnabled" value="true"/>
</settings>
因为 cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。为 true 代表开启二级缓存;为
false 代表不开启二级缓存。
配置相关的 Mapper 映射文件
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.offcn.dao.EmployeeDao">
<!-- 开启二级缓存的支持 -->
<cache></cache>
</mapper>
配置 statement 上面的 useCache 属性
<select id="getEmployeeById" resultMap="EmployeeResultMap" useCache="true">
SELECT * FROM employee WHERE e_id=#{id}
</select>
<resultMap id="EmployeeResultMap" type="Employee">
<id column="e_id" property="id"></id>
<result column="e_name" property="name"></result>
<result column="e_gender" property="gender"></result>
<result column="e_age" property="age"></result>
</resultMap>
将 EmployeeDao.xml 映射文件中的<select>标签中设置 useCache=”true”代表当前这个 statement 要使用二级缓存,如果不使用二级缓存可以设置为 false。
注意:针对每次查询都需要最新的数据 sql,要设置成 useCache=false,禁用二级缓存。
二级缓存测试
public static void secondCahce(){
SqlSession session1 = MyBatisUtils.getSession();
SqlSession session2 = MyBatisUtils.getSession();
EmployeeMapper employeeMapper1=session1.getMapper(EmployeeMapper.class);
//第一次查询
Employee employee1=employeeMapper1.getEmployeeById(1);
System.out.println(employee1.getName());
session1.commit();
MyBatisUtils.close(session1);
//第二次查询
EmployeeMapper employeeMapper2=session2.getMapper(EmployeeMapper.class);
Employee employee2=employeeMapper2.getEmployeeById(1);
System.out.println(employee2.getName());
session2.commit();
MyBatisUtils.close(session2);
}
经过上面的测试,我们发现执行了两次查询,并且在执行第一次查询后,我们关闭了一级缓存,再去执行第二
次查询时,我们发现并没有对数据库发出 sql 语句,所以此时的数据就只能是来自于我们所说的二级缓存。
MyBatis分页插件
分页插件的介绍
分页是一种将所有数据分段展示给用户的技术.用户每次看到的不是全部数据,而是其中的一部分,如果在其中没有找到自己想要的内容,用户可以通过制定页码或是翻页的方式转换可见内容,直到找到自己想要的内容为止。
分页的的好处:
1.提高性能,一次查20个,比一次查20000个性能肯定更好;另外如果数据量很大,一次性将内容都查询出来,查询出来的结果是放在内存存里面的,会增加cpu的开销造成内存的浪费,效率极低。
2.展现层面的考虑:如果一次展现太多的数据,不管是排版,还是美观上都不好。
分页插件的引入和配置
1.在pom.xml中引入插件依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.10</version>
</dependency>
2.在mybatis核心配置文件中进行配置
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
定义接口方法getInfo
public class EmployeeDao{
public void getInfo();
}
配置sql语句对应接口方法
<select id="getInfo" resultType="cn.offcn.entity.Employee">
SELECT * FROM employee
</select>
测试分页插件作用
@Test
public void queryEmployees(){
//在查询前设置当前页与每页显示的记录数
PageHelper.startPage(1,5);
SqlSession session = MyBatisUtils.getSession();
EmployeeDao employeeDao=session.getMapper(EmployeeDao.class);
//查询
List<Employee> employeeList=employeeDao.getInfo();
//创建一个PageInfo对象,把查询出的结果集合当做参数传入
PageInfo<Employee> pageInfo=new PageInfo<>(employeeList);
List<Employee> empList=pageInfo.getList(); //取当前页的所有记录
long totalRecored=pageInfo.getTotal();//总记录数
int totalPages=pageInfo.getPages(); //总页数
System.out.println("总记录数:"+totalRecored);
System.out.println("总页数:"+totalPages);
for (Employee employee : empList) {
System.out.println(employee);
}
session.commit();
MyBatisUtils.close(session);
}
MyBatis的注解开发
注解开发的背景介绍
注解提供了一种简单的方式来实现简单映射语句,而不会引入大量的开销。能够读懂别人写的代码,特别是框架相关的代码。本来可能需要很多配置文件,需要很多逻辑才能实现的内容,就可以使用一个或者多个注解来替代,这样就使得编程更加简洁,代码更加清晰。
常用注解介绍
这几年来注解开发越来越流行,Mybatis 也可以使用注解开发方式,这样我们就可以减少编写 Mapper 映射文件了。本次我们先围绕一些基本的 CRUD 来学习,再学习复杂映射关系及延迟加载。
@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与@Result 一起使用,封装多个结果集
@ResultMap:实现引用@Results 定义的封装
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
@SelectProvider: 实现动态 SQL 映射
@CacheNamespace:实现注解二级缓存的使用
项目环境搭建
构建maven工程,导入依赖
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
使用 Mybatis 注解实现基本 CRUD
编写实体类
public class Worker {
private Integer id;
private String name;
private String gender;
private Integer age;
public Worker(){}
public Worker(String name, String gender, Integer age) {
this.name = name;
this.gender = gender;
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Worker{" +
"id=" + id +
", name='" + name + '\'' +
", gender='" + gender + '\'' +
", age=" + age +
'}';
}
}
使用注解方式开发持久层接口
public interface WorkerMapper {
@Insert("insert into worker (w_name,w_gender,w_age) " +
"values(#{name},#{gender},#{age})")
public void saveWorker(Worker worker);
@Update("update worker set w_name=#{name},w_gender=#{gender},w_age=#{age} where w_id=#{id}")
public void updateWorker(Worker worker);
@Delete("delete from worker where w_id=#{id}")
public void deleteWorkerById(Integer id);
@Select("select * from worker where w_id=#{id}")
@Results({
@Result(column = "w_id",property="id"),
@Result(column = "w_name",property="name"),
@Result(column = "w_gender",property="gender"),
@Result(column = "w_age",property="age")
})
public Worker getWorkerById(Integer id);
@Select("select * from worker")
@Results({
@Result(column = "w_id",property="id"),
@Result(column = "w_name",property="name"),
@Result(column = "w_gender",property="gender"),
@Result(column = "w_age",property="age")
})
public List<Worker> getWorkers();
}
编写 SqlMapConfig 配置文件
<?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的环境 -->
<environments default="development">
<!-- 配置环境 -->
<environment id="development">
<!-- 配置事务的类型 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置连接数据库的信息:用的是数据源【连接池】-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis002"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="cn.offcn.dao"></package>
</mappers>
</configuration>
编写测试方法
import cn.offcn.dao.WorkerMapper;
import cn.offcn.entity.Worker;
import cn.offcn.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class WorkerTest {
@Test
public void testSaveWorker(){
SqlSession session = MyBatisUtils.getSession();
WorkerMapper workerMapper = session.getMapper(WorkerMapper.class);
Worker worker=new Worker("白晓云","女",20);
workerMapper.saveWorker(worker);
session.commit();
MyBatisUtils.close(session);
}
@Test
public void testUpdateWorker(){
SqlSession session = MyBatisUtils.getSession();
WorkerMapper workerMapper = session.getMapper(WorkerMapper.class);
Worker worker=new Worker(1,"白晓云","男",22);
workerMapper.updateWorker(worker);
session.commit();
MyBatisUtils.close(session);
}
@Test
public void testDeleteWorkerById(){
SqlSession session = MyBatisUtils.getSession();
WorkerMapper workerMapper = session.getMapper(WorkerMapper.class);
workerMapper.deleteWorkerById(1);
session.commit();
MyBatisUtils.close(session);
}
@Test
public void testGetWorkerById(){
SqlSession session = MyBatisUtils.getSession();
WorkerMapper workerMapper = session.getMapper(WorkerMapper.class);
Worker worker= workerMapper.getWorkerById(2);
System.out.println(worker);
MyBatisUtils.close(session);
}
@Test
public void testGetWorkers(){
SqlSession session = MyBatisUtils.getSession();
WorkerMapper workerMapper = session.getMapper(WorkerMapper.class);
List<Worker> workerList=workerMapper.getWorkers();
workerList.forEach(System.out::println);
MyBatisUtils.close(session);
}
}
使用注解实现复杂关系映射开发
复杂关系映射的注解介绍
@Results 注解
代替的是标签<resultMap>
该注解中可以使用单个@Result 注解,也可以使用@Result 集合
@Results({@Result(),@Result()})或@Results(@Result())
@Resutl 注解
代替了 <id> 标签和<result> 标签
@Result 中 属性介绍:
id 是否是主键字段
column 数据库的列名
property 需要装配的属性名
one 需要使用的@One 注解(@Result(one=@One)()))
many 需要使用的@Many 注解(@Result(many=@many)()))
@One 注解(一对一)
代替了<assocation> 标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
@One 注解属性介绍:
select 指定用的 来多表查询的 sqlmapper
fetchType 会覆盖全局的配置参数 lazyLoadingEnabled。
使用格式:
@Result(column=" ",property="",one=@One(select=""))
@Many 注解(多对一)
代替了<Collection> 标签, 是是多表查询的关键,在注解中用来指定子查询返回对象集合。
注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType
(一般为 ArrayList)但是注解中可以不定义;
使用格式:
@Result(property="",column="",many=@Many(select=""))
使用注解实现一对一复杂关系映射及延迟加载
添加 Person实体类及 IdCard 实体类
Person实体类:
public class Person {
private int id;
private String name;
private IdCard idCard;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public IdCard getIdCard() {
return idCard;
}
public void setIdCard(IdCard idCard) {
this.idCard = idCard;
}
}
IdCard实体类:
public class IdCard {
private int id;
private String cardno;
private Date useLife;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCardno() {
return cardno;
}
public void setCardno(String cardno) {
this.cardno = cardno;
}
public Date getUseLife() {
return useLife;
}
public void setUseLife(Date useLife) {
this.useLife = useLife;
}
}
添加IdCard的持久层接口并使用注解配置
public interface IdCardMapper {
@Select("select * from idcard where c_id=#{id}")
@Results({
@Result(column = "c_id",property = "id"),
@Result(column = "c_cardno",property = "cardno"),
@Result(column = "e_uselife",property = "useLife")
})
public IdCard getIdCardByPersonId(int id);
}
添加Person持久层接口并使用注解配置
public interface PersonMapper {
@Select(select * from person where p_id=#{id})
@Results({
@Result(column = "p_id",property = "id"),
@Result(column = "p_name",property = "name"),
@Result(property = "idCard",
javaType = IdCard.class,
column = "p_id",
one = @One(select = "cn.offcn.dao.IdCardDao.getIdCardByPersonId",fetchType = FetchType.LAZY)
)
})
public Person getPersonById(int id);
}
测试一对一关联及延迟加载
@Test
public void testGetPersonById(){
SqlSession session=MyBatisUtils.getSession();
PersonMapper personMapper=session.getMapper(PersonMapper.class);
Person person=personMapper.getPersonById(1);
System.out.println(person)
MyBatisUtils.close(session);
}
使用注解实现一对多复杂关系映射
构建Department和Employee实体类
Department实体类:
public class Department {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Employee实体类:
public class Employee {
private int id;
private String name;
private String gender;
private Integer age;
public Employee(){}
public Employee(int id,String name, String gender, int age) {
this.id=id;
this.name = name;
this.gender = gender;
this.age = age;
}
public Employee(String name, String gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
Department实体类加入 List<Employee>
private List<Employee> emps;
public List<Employee> getEmps() {
return emps;
}
public void setEmps(List<Employee> emps) {
this.emps = emps;
}
编写EmployeeMapper持久层接口并使用注解配置
public interface EmployeeMapper{
@Select("select * from employee where e_depart_id=#{id}")
@Results({
@Result(column = "e_id",property = "id"),
@Result(column = "e_name",property = "name"),
@Result(column = "e_gender",property = "gender"),
@Result(column = "e_age",property = "age")
})
public List<Employee> getEmployeeByDepartId(int id);
}
编写DepartmentMapper持久层接口并使用注解配置
public interface DepartmentDao {
@Select("select d_id id,d_name name from department where d_id=#{id}")
public Department getDepartmentById(int id);
@Select("select * from department where d_id=#{id}")
@Results({
@Result(column = "d_id",property = "id"),
@Result(column = "d_name",property = "name"),
@Result(property = "emps",
column = "d_id",
many = @Many(select = "cn.offcn.dao.EmployeeMapper.getEmployeeByDepartId",fetchType = FetchType.LAZY))
})
public Department getDepartmentById(int id);
}
添加测试方法
public void testGetDepartmentById(){
SqlSession session=MyBatisUtils.getSession();
DepartmentMapper departmentMapper=session.getMapper(DepartmentMapper.class);
Department department=departmentMapper.getDepartmentById(1);
System.out.println(department)
MyBatisUtils.close(session);
}