2022-05-25  2022-05-25    6398 字   13 分钟

延迟加载策略

延迟加载的简介:什么是延迟加载,为什么要使用延迟加载

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);
    
 }

avatar
青山
悟已往之不谏 知来者之可追
一言
今日诗词
站点信息
本站访客数 :
本站总访问量 :