第16节:延迟加载策略
首先说明什么是延迟加载及应用场景。特别要说明mybatis应用延迟加载的前得条件必须是嵌套方式才可以。其次解释使用延迟加载可减少访问数据库的频率,减少系统资源的消耗从而提高mybatis查询性能。分别介绍局部延迟加载和全局延迟加载的配置。
16.1 延迟加载的简介
1. 什么是延迟加载?
延迟加载( lazy load) 是( 也称为懒加载) 关联关系对象默认的加载方式,延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作。
延迟加载,可以简单理解为,只有在使用的时候,才会发出sql语句进行查询。
2. 为什么要使用延迟加载?
减少访问数据库的频率,我们要访问的数据量过大时,明显用缓存不太合适,因为内存容量有限为了减少并发量,减少系统资源的消耗。
16.2 配置延迟加载
在mybatis中使用resultMap来实现一对一,一对多,多对多关系的操作。主要是通过 association、collection 实现一对一及一对多映射。association、collection 具备延迟加载功能。
16.2.1 局部延时加载
1)配置文件
< 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为延时加载。
2)测试类
@Test
public void testGetDepartentById ( ) throws Exception {
SqlSession session = MyBatisUtils . getSession ( ) ;
DepartmentDao departmentDao = session. getMapper ( DepartmentDao . class ) ;
Department dept= departmentDao. getDepartentById ( 1 ) ;
System . out. println ( dept. getName) ;
session. commit ( ) ;
MyBatisUtils . close ( session) ;
}
16.2.2 全局延时加载
如果希望所有关联都需要延时加载,可以在mybatis的核心配置文件中进行配置,不用在collection或association中指定。默认全局开启。
< settings>
< setting name = " lazyLoadingEnabled" value = " true" />
< setting name = " aggressiveLazyLoading" value = " false" />
</ settings>
第17节:逆向工程
首先解我们企业开发中是先进行数据建模即建库建表并设定表和表之间的关系。可以举方活中的列子,如盖楼先有图纸,才能盖楼,而不是先盖楼再画图纸。mybatis考虑到对单表进行CRUD时,对于映射文件来讲只是标签和sql语句的不同,所以提供了逆向工程,可以通过表直接生成实体类、接口、接口的映射文件,来减轻开人员工作量,提高开发效率。接着可据官方文档搭建项目环境,编写逆向工程的配置文件、最后进行测试。
17.1 介绍
MyBatis 的一个主要的特点就是需要程序员自己编写sql,那么如果表太多的话,难免会很麻烦,所以mybatis官方提供了一个逆向工程,可以针对单表自动生成mybatis执行所需要的代码(包括mapper. xml、mapper. java、pojo)。一般在开发中,常用的逆向工程方式是通过数据库的表生成代码。
17.2 使用
17.2.1 构建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>
17.2.2 编写配置框架配置文件
?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>
< mappers>
< package name = " cn.offcn.mapper" > </ package>
</ mappers>
</ configuration>
17.2.3 编写配置文件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>
< property name = " suppressAllComments" value = " true" />
</ commentGenerator>
< jdbcConnection driverClass = " com.mysql.jdbc.Driver"
connectionURL = " jdbc:mysql://localhost:3306/mybatis828_002"
userId = " root" password = " root" >
< property name = " nullCatalogMeansCurrent" value = " true" />
</ jdbcConnection>
< javaTypeResolver>
< property name = " forceBigDecimals" value = " false" />
</ javaTypeResolver>
< javaModelGenerator targetPackage = " cn.offcn.entity"
targetProject = " 项目名\src\main\java" >
< property name = " enableSubPackages" value = " false" />
< property name = " trimStrings" value = " true" />
</ javaModelGenerator>
< sqlMapGenerator targetPackage = " cn.offcn.mapper"
targetProject = " 项目名\src\main\java" >
< property name = " enableSubPackages" value = " false" />
</ sqlMapGenerator>
< javaClientGenerator type = " XMLMAPPER"
targetPackage = " cn.offcn.mapper"
targetProject = " 项目名\src\main\java" >
< 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>
17.2.4 调用官方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 callback = new DefaultShellCallback ( overwrite) ;
MyBatisGenerator myBatisGenerator = new MyBatisGenerator ( config,
callback, warnings) ;
myBatisGenerator. generate ( null ) ;
}
17.2.5 使用逆向工程完成数据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) ;
}
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) ;
}
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) ;
}
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 ) ;
}
第18节:缓存
本章首先介绍什么是缓存,为什么要使用缓存即提高mybatis查询性能。分别介绍一级缓存和二级缓存的应用场景并对数据存储进行分析。对于缓存数据存储要以画图的方式进行描述。
18.1 缓存简介
缓存是存在于内存中的临时数据,使用缓存的目的是减少和数据库的交互次数,提高执行效率。像大多数的持久化框架一样,Mybatis 也提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提高性能,Mybatis 中缓存分为一级缓存,二级缓存。
18.2 一级缓存
18.2.1 介绍
mybatis一级缓存一种是SESSION级别的,针对同一个会话SqlSession 中,执行多次条件完全相同的同一个sql,那么会共享这一缓存。
18.2.2 一级缓存结构图
18.2.3 编写持久层接口
public interface EmployeeDao {
public Employee getEmployeeById ( int id) ;
}
18.2.4 编写映射文件
< 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>
18.2.5 编写测试方法
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) ;
}
18.2.6 一级缓存的分析
从上面的代码可以出,我们写了两次查询操作,但在访问数据时,只有一次。第一次先从一级缓存中获取,因为session是新创建的,一级缓存中没有数据,于是就查询数据获取数据,然后把查询的数据放到一级缓存中,此时一定要注意的是,一级缓存是一个Map 集合,map的key是你的查询条件字符串,值就是查询出来的对象。等第二次查询时,先从一缓存中获取,因为上一次查询后已经放到一级缓存中了,所以从一级缓存中获取到了,就不用访问数据库了,减少和数据次的一次交互,提高了执行效率。
18.2.7 测试一级缓存的清空
当我们在两次查询之间做增、删、改操作都会把一级缓存清空,因为不清空就不能保证缓存中的数据与数据库中数据的一致性,可能会读取不正确的数据。
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) ;
}
18.3 二级缓存
18.3.1 二级缓存简介
二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个
SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。
18.3.2 二级缓存结构图
18.3.3 二级缓存的开启与关闭
1)主配置文件开启二级缓存
< settings>
< setting name = " cacheEnabled" value = " true" />
</ settings>
因为 cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。为 true 代表开启二级缓存;为
false 代表不开启二级缓存。
2)配置相关的 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>
3)配置 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,禁用二级缓存。
4)二级缓存测试
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 语句,所以此时的数据就只能是来自于我们所说的二级缓存。
第19节:分页插件
本节讲解分页插件的使用步聚,首先进行分页插件介绍,引入分页配置,对分页的理原进行分析,强调该拦截器在执行sql之前会附加limit关键字,推带分页配置并把分页信息封装到PageInfo 对象中。
19.1 分页插件的介绍
分页是一种将所有数据分段展示给用户的技术. 用户每次看到的不是全部数据, 而是其中的一部分, 如果在其中没有找到自己想要的内容, 用户可以通过制定页码或是翻页的方式转换可见内容, 直到找到自己想要的内容为止。
分页的的好处:
1. 提高性能,一次查20 个,比一次查20000 个性能肯定更好;另外如果数据量很大,一次性将内容都查询出来,查询出来的结果是放在内存存里面的,会增加cpu的开销造成内存的浪费,效率极低。
2. 展现层面的考虑:如果一次展现太多的数据,不管是排版,还是美观上都不好。
19.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>
19.3 定义接口方法
public class EmployeeDao {
public void getInfo ( ) ;
}
19.4 配置接口方法
< select id = " getInfo" resultType = " cn.offcn.entity.Employee" >
SELECT * FROM employee
</ select>
19.5 测试分页插件
@Test
public void queryEmployees ( ) {
PageHelper . startPage ( 1 , 5 ) ;
SqlSession session = MyBatisUtils . getSession ( ) ;
EmployeeDao employeeDao= session. getMapper ( EmployeeDao . class ) ;
List < Employee > employeeList= employeeDao. getInfo ( ) ;
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) ;
}
第20节:注解开发
本节主要介绍注解开发的应用背景及注解开发的流程,首先对注解进行介绍,其次对单表接口进行注解配置并演示运行结果,在讲解一对多和一对一关系注解映射时,要对比xml配置方进行解决,方便学员理解。
20.1 注解开发的背景介绍
注解提供了一种简单的方式来实现简单映射语句, 而不会引入大量的开销。能够读懂别人写的代码,特别是框架相关的代码。本来可能需要很多配置文件,需要很多逻辑才能实现的内容,就可以使用一个或者多个注解来替代,这样就使得编程更加简洁,代码更加清晰。
20.2 常用注解介绍
这几年来注解开发越来越流行,Mybatis 也可以使用注解开发方式,这样我们就可以减少编写 Mapper 映射文件了。本次我们先围绕一些基本的 CRUD 来学习,再学习复杂映射关系及延迟加载。
@Insert : 实现新增
@Update : 实现更新
@Delete : 实现删除
@Select : 实现查询
@Result : 实现结果集封装
@Results : 可以与@Result 一起使用,封装多个结果集
@ResultMap : 实现引用@Results 定义的封装
@One : 实现一对一结果集封装
@Many : 实现一对多结果集封装
@SelectProvider : 实现动态 SQL 映射
@CacheNamespace : 实现注解二级缓存的使用
20.3 使用
20.3.1 构建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>
20.3.2 注解实现基本 CRUD
1)编写实体类
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 +
'}' ;
}
}
2)持久层接口
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 ( ) ;
}
3)编写主配置文件
<?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>
< 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>
4)编写测试方法
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) ;
}
}
20.4 注解实现复杂关系映射
20.4.1 复杂关系映射的注解介绍
@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= "" ) )
20.4.2 一对一复杂关系映射及延迟加载
1)添加 实体类
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;
}
}
2)持久层接口并使用注解配置
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) ;
}
3)持久层接口并使用注解配置
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) ;
}
4)测试一对一关联及延迟加载
@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) ;
}
20.4.3 一对多复杂关系映射
1)构建实体类
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;
}
}
2)Department实体类加入 List
private List < Employee > emps;
public List < Employee > getEmps ( ) {
return emps;
}
public void setEmps ( List < Employee > emps) {
this . emps = emps;
}
3) 持久层接口并使用注解配置
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) ;
}
4)持久层接口并使用注解配置
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) ;
}
5)添加测试方法
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) ;
}