Mybatis 主流的ORM框架,之前叫IBatis后来叫MyBatis,实现数据持久化的框架,同时支持Java .NET, .Ruby三种语言,MyBatis是一个对JDBC进行封装的框架。
ORM 框架 Hibernate,两个的区别:
Hibernate是一个全自动化的ORM框架,MyBatis是一个半自动化的ORM框架
全自动化:开发者只需要调用相关接口就可以完成操作,整个流程框架都已经进行了封装。
Hibernate实现了POJO和数据库表之间的映射,同时可以自动生成SQL语句并完成执行。
半自动化:框架只提供一部分功能,剩下的工作仍需要开发者手动完成,MyBatis没有提供POJO与数据库表的映射,只实现了POJO与SQL的映射关系,需要开发者自定义SQL语句,以及数据与POJO之间的装配关系。
虽然功能上没有Hibernate更加方便但是这种半自动化的方式提高了框架的灵活性
开发者可以根据具体的业务需求完成定制化的持久层解决方案
MyBatis对所有的JDBC进行了封装,包括参数设置,SQL执行,结果集的解析等,通过xml配置的方式或者注解的方式完成POJO与数据的映射。
简单来讲,使用Mybatis进行开发,主要完成两步操作:
自己编写sql
自己完成数据库数据与POJO的映射
MyBatis优点
极大简化JDBC代码的开发
简单好用容易上手,同时具有更好的灵活性
通过将SQL定义在xml中的方式降低程序的耦合性
支持动态SQL可以根据具体的业务需求灵活实现功能
MyBatis缺点
相比于Hibernate,开发者需要完成更多工作比如定义SQL语句,设置POJO与数据的映射关系
要求开发人员具备一定的SQL编写能力,在一些特定场景下工作量比较大
数据库的移植性比较差,因为SQL依赖于底层数据库,部分SQL语句需要重新编写。
MyBatis入门 1、创建Maven工程,在pom.xml中引入依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <?xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <groupId > com.bitzh</groupId > <artifactId > mybatis</artifactId > <version > 1.0-SNAPSHOT</version > <properties > <maven.compiler.source > 17</maven.compiler.source > <maven.compiler.target > 17</maven.compiler.target > <project.build.sourceEncoding > UTF-8</project.build.sourceEncoding > </properties > <dependencies > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.4.5</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.19</version > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.18.30</version > </dependency > </dependencies > </project >
2、创建实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package com.bitzh.entity;import lombok.Data;@Data public class People { private Integer id; private String name ; private Double money; }
3、配置MyBatis环境,在resources路径下创建config.xml(可以自定义),配置数据源信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?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" /> <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.cj.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/test?useUnicode=true& characterEncoding=utf8& useSSL=false& serverTimezone=UTC" /> <property name ="username" value ="root" /> <property name ="password" value ="root" /> </dataSource > </environment > </environments > </configuration >
4、MyBatis 开发有两种方式
使用原生接口 1、创建Mapper文件PeopleMapper.xml
1 2 3 4 5 6 7 8 9 10 <?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" > <mapper namespace ="com.bitzh.mapper.PeopleMapper" > <select id ="findById" parameterType ="java.lang.Integer" resultType ="com.bitzh.entity.People" > select * from people where id = #{id} </select > </mapper >
namespace:通常设置为文件所在包的包名+文件名,parameterType是参数的数据类型
resultType:是返回值的数据类型
2、在全局配置文件config.xml中注册PeopleMapper.xml
1 2 3 <mappers > <mapper resource ="com/bitzh/mapper/PeopleMapper.xml" > </mapper > </mappers >
3、调用api完成操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package com.bitzh.test;import com.bitzh.entity.People;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.InputStream;public class Test { public static void main (String[] args) { InputStream inputStream = Test.class.getClassLoader().getResourceAsStream("config.xml" ); SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder (); SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); String statement = "com.bitzh.mapper.PeopleMapper.findById" ; People people = sqlSession.selectOne(statement, 1 ); System.out.println(people); sqlSession.close(); } }
4、IDEA中无法直接读取resources路径下的xml文件需要再pom.xml中进行设置
1 2 3 4 5 6 7 8 9 10 <build > <resources > <resource > <directory > src/main/java</directory > <includes > <include > **/*.xml</include > </includes > </resource > </resources > </build >
Mapper代理实现自定义接口 开发者只需要定义接口,并不需要实现接口,具体的实现工作由Mapper代理结合配置文件完成。
1、自定义接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.bitzh.repository;import com.bitzh.entity.People;import java.util.List;public interface PeopleRepository { public int save (People people) ; public int deleteById (Integer id) ; public int update (People people) ; public People findById (Integer id) ; public List<People> findAll () ; }
2、创建PeopleMapper.xml定义接口方法对应的SQL语句statement标签根据SQL执行的业务可以选择select\insert\delete\update,MyBatis会根据规则 创建PeopleRepository接口的实现类代理对象。
规则如下:
PeopleMapper.xml中的namespace必须是接口的全限定类名(带着包名的类名)
PeopleMapper.xml中的statement的id是接口中对应的方法名
PeopleMapper.xml中parameterType和接口中对应方法的参数类型一致
PeoplMapper.xml中的resultType和接口中对应方法的返回值类型一致
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?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" > <mapper namespace ="com.bitzh.repository.PeopleRepository" > <insert id ="save" parameterType ="com.bitzh.entity.People" > insert into people values(default,#{name},#{money}) </insert > <delete id ="deleteById" parameterType ="java.lang.Integer" > delete from people where id = #{id} </delete > <update id ="update" parameterType ="com.bitzh.entity.People" > update people set name = #{name},money = #{money} where id = #{id} </update > <select id ="findById" parameterType ="java.lang.Integer" resultType ="com.bitzh.entity.People" > select * from people where id = #{id} </select > <select id ="findAll" resultType ="com.bitzh.entity.People" > select * from people </select > </mapper >
3、完成注册
1 2 3 4 <mappers > <mapper resource ="com/bitzh/mapper/PeopleMapper.xml" > </mapper > <mapper resource ="com/bitzh/repository/PeopleRepository.xml" > </mapper > </mappers >
4、调用api
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package com.bitzh.test;import com.bitzh.entity.People;import com.bitzh.repository.PeopleRepository;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.InputStream;import java.util.List;public class Test2 { public static void main (String[] args) { InputStream inputStream = Test2.class.getClassLoader().getResourceAsStream("config.xml" ); SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder (); SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); PeopleRepository peopleRepository = sqlSession.getMapper(PeopleRepository.class); List<People> list = peopleRepository.findAll(); for (People people:list){ System.out.println(people); } sqlSession.commit(); sqlSession.close(); } }
Mapper.xml常用配置 MyBatis的配置文件有两种
全局环境配置文件(数据源,事务管理,mapper的注册,打印sql,惰性加载,二级缓存。。。)
Mapper配置文件(定义自定义接口的具体实现方案,sql,数据与pojo的映射)
多表关联查询包括一对一,一对多,多对多三种
单表查询 1 2 3 <select id ="findById" parameterType ="java.lang.Integer" resultType ="com.bitzh.entity.People" > select * from people where id = #{id} </select >
业务:通过id查询People对象
目标表:test/people
实体类:com.bitzh.entity.People
Mapper.xml直接拍每个设置相关配置逻辑,用MyBatis自动完成查询,生成POJO
statement标签主要属性有id、parameterType、resultType
id对应接口方法名,parameterType定义参数的数据类型,resultType定义查询结果的数据类型(实体类的成员变量列表必须与目标表的字段列表一致)
parameterType 支持基本数据类型、包装类、String、多参数、POJO等。
1、基本数据类型,通过id查询POJO。
1 public People findById (int id) ;
1 2 3 <select id ="findById" parameterType ="int" resultType ="com.bitzh.entity.People" > select * from people id = #{id} </select >
2、包装类
1 2 3 <select id="findById" parameterType="java.lang.Integer" resultType="com.bitzh.entity.People" > select * from people where id = #{id} </select>
3、String类型
1 public People findByName (String name) ;
1 2 3 <select id ="findByName" parameterType ="java.lang.String" resultType ="com.bitzh.entity.People" > select * from people where name = #{name} </select >
4、多参数、
1 public People findByIdAndName (Integer id,String name) ;
1 2 3 <select id ="findByIdAndName" resultType ="com.bitzh.entity.People" > select * from people where id=#{param1} and name=#{param2} </select >
5、POJO
也是一样的
resultType resultType与parameter的使用基本一致
多表关联查询 实际开发中最常用的是:一对多和多对多
一对多 1、建表
1 2 3 4 5 6 7 8 9 10 11 12 create table t_classes( id int (11 ) not null primary key auto_increment, name varchar (11 ) default NULL ); create table t_student( id int (11 ) not null primary key auto_increment, name varchar (11 ) default null , cid int (11 ) default null , constraint t_student_ibfk foreign key (cid) references t_classes(id) );
2、SQL
1 2 3 4 5 select s.id sid ,s.name sname,s.cid,t.name cnamefrom t_student sinner join t_classes t on s.cid = t.idwhere s.id = 1
3、创建实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package com.bitzh.entity;import lombok.Data;@Data public class Student { private Integer id; private String name; private Classes classes; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package com.bitzh.entity;import lombok.Data;@Data public class Classes { private Integer id; private String name; private List<Student> student; }
4、StudentRepository接口
1 2 3 public interface StudentRepository { public Student findById (Integer id) ; }
5、StudentRepository.xml
resultType直接将结果集与实体类进行映射,结果集的字段名与实体类的成员变量名相等则映射。
resultMap 可以对结果集进行二次封装,根据需求来完成结果集数据到实体类的映射。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?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" > <mapper namespace ="com.bitzh.repository.StudentRepository" > <resultMap id ="studentMap" type ="com.bitzh.entity.Student" > <id column ="sid" property ="id" > </id > <result column ="sname" property ="name" > </result > <association property ="classes" javaType ="com.bitzh.entity.Classes" > <id column ="cid" property ="id" > </id > <result column ="cname" property ="name" > </result > </association > </resultMap > <select id ="findById" parameterType ="java.lang.Integer" resultMap ="studentMap" > select s.id sid ,s.name sname,s.cid,t.name cname from t_student s inner join t_classes t on s.cid = t.id where s.id = 1 </select > </mapper >
6、ClassesRepository
1 2 3 4 public interface ClassesRepository { public Classes findById (Integer id) ; }
7、ClassesRepository.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?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" > <mapper namespace ="com.bitzh.repository.ClassesRepository" > <resultMap id ="classesMap" type ="com.bitzh.entity.Classes" > <id column ="cid" property ="id" > </id > <result column ="cname" property ="name" > </result > <collection property ="student" ofType ="com.bitzh.entity.Student" > <id property ="id" column ="sid" > </id > <result column ="sname" property ="name" > </result > </collection > </resultMap > <select id ="findById" parameterType ="java.lang.Integer" resultMap ="classesMap" > select c.id cid,c.name cname,s.id sid,s.`name` sname from t_classes c inner join t_student s on c.id = s.cid where c.id = 1 </select > </mapper >
collection和association的区别
collection是将结果集封装成一个集合对象(多个目标对象)
association是将结果集封装成一个实体类的对象(一个目标对象)
collection是对ofType设置数据类型,association是通过javaType设置数据类型。
多对多 多对多是双向的一对多关系,(学生选课)
1、建表(多对多外键不能加在任意一张表要新建一个中间表)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 create table t_account( id int (11 ) not null primary key auto_increment, name varchar (11 ) default NULL ); create table t_course( id int (11 ) not null primary key auto_increment, name varchar (11 ) default null ); create table account_course( id int (11 ) not null primary key auto_increment, aid int (11 ) default null , cid int (11 ) default null , constraint account_course_ibfk_1 foreign key (aid) references t_account(id), constraint account_course_ibfk_2 foreign key (cid) references t_course(id) );
2、创建实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.bitzh.entity;import lombok.Data;import java.util.List;@Data public class Course { private Integer id; private String name; List<Account> accounts; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package com.bitzh.entity;import lombok.Data;import java.util.List;@Data public class Account { private Integer id; private String name; private List<Course> courses; }
3、AccountRepository
1 2 3 public interface AccountRepository { public Account findById (Integer id) ; }
4、AccountRepository.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <?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" > <mapper namespace ="com.bitzh.repository.AccountRepository" > <resultMap id ="accountMap" type ="com.bitzh.entity.Account" > <id column ="aid" property ="id" > </id > <result column ="aname" property ="name" > </result > <collection property ="courses" ofType ="com.bitzh.entity.Course" > <id column ="cid" property ="id" > </id > <result column ="cname" property ="name" > </result > </collection > </resultMap > <select id ="findById" parameterType ="java.lang.Integer" resultMap ="accountMap" > select a.id aid,a.name aname,c.id cid,c.`name` cname from account_course ac inner join t_course c on c.id = ac.cid inner join t_account a on a.id = ac.aid where a.id=1; </select > </mapper >
5、CourseRepository
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.bitzh.repository;import com.bitzh.entity.Course;public interface CourseRepository { public Course findById (Integer id) ; }
6、CourseRepository.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?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" > <mapper namespace ="com.bitzh.repository.CourseRepository" > <resultMap id ="courseMap" type ="com.bitzh.entity.Course" > <id column ="cid" property ="id" > </id > <result column ="cname" property ="name" > </result > <collection property ="accounts" ofType ="com.bitzh.entity.Account" > <id column ="aid" property ="id" > </id > <result column ="aname" property ="name" > </result > </collection > </resultMap > <select id ="findById" parameterType ="java.lang.Integer" resultMap ="courseMap" > select a.id aid,a.name aname,c.id cid,c.`name` cname from account_course ac inner join t_course c on c.id = ac.cid inner join t_account a on a.id = ac.aid where c.id=1 </select > </mapper >
Mybatis逆向工程 MyBatis是半自动化的ORM框架,SQL语句需要开发者自定义,SQL需要单独定义在Mapper.xml中,需要与Mapper接口对应,使用MyBatis进行开发的基本配置:
这种方法的缺陷是如果参与业务的表太多,每张表的业务都需要自定义SQL语句,创建实体类,以及Mapper接口,工作量较大。
MyBatis框架可以自动根据数据表帮助开发者生成实体类,Mapper接口,Mapper.xml,这就是逆向工程。
逆向工程概念 逆向工程是MyBatis提供的一种自动化配置方案,针对数据表自动生成MyBatis所需要的各种资源(实体类,Mapper接口,Mapper.xml)但是逆向工程化只针对于单表,如果数据表之间有级联关系,逆向工程无法自动生成级联关系。
使用逆向工程 MyBatis逆向工程的组件是MyBatis Generator,简称MBG,是专门为MyBatis框架定值的代码自动生成解决方案,MBG可以根据数据表结构快速生成对应的实体类,Mapper接口,Mapper.xml,并且支持基本的CRUD操作,但是业务逻辑相对复杂的操作需要手动完成
1、创建Maven工程,pom.xml添加相关依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <dependencies > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.4.5</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.19</version > </dependency > <dependency > <groupId > org.mybatis.generator</groupId > <artifactId > mybatis-generator-core</artifactId > <version > 1.3.2</version > </dependency > </dependencies >
2、创建目标表Account
1 2 3 4 5 6 7 CREATE TABLE `t_account` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar (11 ) DEFAULT NULL , `password` varchar (11 ) DEFAULT NULL , `age` int DEFAULT NULL , PRIMARY KEY (`id`) ) ENGINE= InnoDB AUTO_INCREMENT= 4 DEFAULT CHARSET= utf8mb4 COLLATE = utf8mb4_0900_ai_ci
3、创建MBG配置文件generatorConfig.xml
jdbcConnection配置数据库链接信息
javaModelGenerator配置javaBean的生成策略
sqlMapGenerator配置SQL映射文件生成策略
javaClientGenerator配置Mapper接口的生成策略
table配置需要逆向解析的数据表(tableName:表名,domainObjectName:实体类名)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <?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" > <jdbcConnection driverClass ="com.mysql.cj.jdbc.Driver" connectionURL ="jdbc:mysql://localhost:3306/test?useUnicode=true& characterEncoding=utf8& useSSL=false& serverTimezone=UTC" userId ="root" password ="root" > </jdbcConnection > <javaModelGenerator targetPackage ="com.bitzh.entity" targetProject =".\src\main\java" > </javaModelGenerator > <sqlMapGenerator targetPackage ="com.bitzh.repository" targetProject =".\src\main\java" > </sqlMapGenerator > <javaClientGenerator type ="XMLMAPPER" targetPackage ="com.bitzh.repository" targetProject =".\src\main\java" > </javaClientGenerator > <table tableName ="t_account" domainObjectName ="Account" /> </context > </generatorConfiguration >
4、创建GeneratorMain类,执行自动生成资源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 package com.bitzh.test;import java.io.File;import java.io.IOException;import java.sql.SQLException;import java.util.ArrayList;import java.util.List;import org.mybatis.generator.api.MyBatisGenerator;import org.mybatis.generator.config.Configuration;import org.mybatis.generator.config.xml.ConfigurationParser;import org.mybatis.generator.exception.InvalidConfigurationException;import org.mybatis.generator.exception.XMLParserException;import org.mybatis.generator.internal.DefaultShellCallback;public class GeneratorMain { public static void main (String[] args) { List<String> warnings = new ArrayList <>(); boolean overwrite = true ; String genCig = "/generatorConfig.xml" ; File configFile = new File (GeneratorMain.class.getResource(genCig).getFile()); ConfigurationParser configurationParser = new ConfigurationParser (warnings); Configuration configuration = null ; try { configuration = configurationParser.parseConfiguration(configFile); } catch (IOException e) { e.printStackTrace(); } catch (XMLParserException e) { e.printStackTrace(); } DefaultShellCallback callback = new DefaultShellCallback (overwrite); MyBatisGenerator myBatisGenerator = null ; try { myBatisGenerator = new MyBatisGenerator (configuration, callback, warnings); } catch (InvalidConfigurationException e) { e.printStackTrace(); } try { myBatisGenerator.generate(null ); } catch (SQLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }
MyBatis延迟加载 1、创建实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package com.bitzh.entity;import lombok.Data;import java.util.List;@Data public class Customer { private Integer id; private String name; List<Order> orders; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package com.bitzh.entity;import lombok.Data;@Data public class Order { private Integer id; private String name; private Customer customer; }
2、配置打印sql,在config,xml中
1 2 3 4 <settings > <setting name ="logImpl" value ="STDOUT_LOGGING" /> </settings >
3、创建OrderRepository
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?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" > <mapper namespace ="com.bitzh.repository.OrderRepository" > <resultMap id ="orderMap" type ="com.bitzh.entity.Order" > <id column ="id" property ="id" > </id > <result column ="name" property ="name" > </result > <association property ="customer" javaType ="com.bitzh.entity.Customer" select ="com.bitzh.repository.CustomerRepository.findById" column ="cid" > </association > </resultMap > <select id ="findById" parameterType ="java.lang.Integer" resultMap ="orderMap" > select * from orders where id = #{id} </select > </mapper >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.bitzh.repository;import com.bitzh.entity.Order;public interface OrderRepository { public Order findById (Integer id) ; }
4、创建CustomerRepository
1 2 3 4 5 6 7 8 9 10 <?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" > <mapper namespace ="com.bitzh.repository.CustomerRepository" > <select id ="findById" parameterType ="java.lang.Integer" resultType ="com.bitzh.entity.Customer" > select * from customers where id = #{id} </select > </mapper >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.bitzh.repository;import com.bitzh.entity.Customer;public interface CustomerRepository { public Customer findById (Integer id) ; }
5、config.xml中开启延迟加载
1 2 3 4 5 6 <settings > <setting name ="logImpl" value ="STDOUT_LOGGING" /> <setting name ="lazyLoadingEnabled" value ="true" /> </settings >
如果设置懒加载后报错可能是mybatis版本太低!
MyBatis延迟加载机制,实际开发中使用频率较高的一个功能,正确的使用延迟加载,可以有效的减少java Application和数据库的交互次数,从而提高整个系统的运行效率,延迟加载是为了提高程序运行效率的一种手段,一般应用于多表关联查询的业务场景。
MyBatis缓存 使用缓存的作用也是为了减少Java Application与数据库的交互次数,从而提升程序的运行效率。
MyBatis有两种缓存:一级缓存和二级缓存。
一级缓存 MyBatis自带一级缓存,并且是无法关闭的,一直存在,一级缓存的数据存储在SqlSession中。
即使用同一个SqlSession进行查询操作的时候,一级缓存存在,如果说使用多个SqlSession进行查询操作,一级缓存不存在,缓存只针对于查询操作但是如果SqlSession执行了增删改操作,那么MyBatis会自动清空SqlSession缓存中的数据,以此来保证数据的一致性。
一级缓存不需要进行任何配置,直接使用即可。
1、创建实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package com.bitzh.entity;import lombok.Data;@Data public class MyClass { private Integer id; private String name; }
2、创建Mapper接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.bitzh.repository;import com.bitzh.entity.MyClass;public interface MyClassRepository { public MyClass findById (Integer id) ; }
3、创凯MyClassRepository.xml
1 2 3 4 5 6 7 8 9 10 11 <?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" > <mapper namespace ="com.bitzh.repository.MyClassRepository" > <select id ="findById" parameterType ="java.lang.Integer" resultType ="com.bitzh.entity.MyClass" > select * from t_classes where id =#{id} </select > </mapper >
如图开了一级缓存执行了一次sql语句。
如果关闭sqlSession,开启新的sqlSession的话,sql语句就会执行两次。
二级缓存 MyBatis二级缓存是比一级缓存作用域更大的缓存机制,它是Mapper级别的,只要是同一个Mapper,无论使用了多少个SqlSession,数据都是共享的。
MyBatis二级缓存默认是关闭的,需要使用时
可以通过配置手动开启。
MyBatis可以使用自带的二级缓存,也可以使用第三方的ehcache二级缓存。
自带的二级缓存
1、config.xml中配置开启二级缓存
1 2 <setting name ="cacheEnabled" value ="true" />
2、在Mapper.xml中配置二级缓存
1 2 3 4 5 6 7 8 9 10 11 12 <?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" > <mapper namespace ="com.bitzh.repository.MyClassRepository" > <cache > </cache > <select id ="findById" parameterType ="java.lang.Integer" resultType ="com.bitzh.entity.MyClass" > select * from t_classes where id =#{id} </select > </mapper >
3、实体类实现序列化接口Serializable
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.bitzh.entity;import lombok.Data;import java.io.Serializable;@Data public class MyClass implements Serializable { private Integer id; private String name; }
4、测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package com.bitzh.test;import com.bitzh.entity.MyClass;import com.bitzh.entity.Order;import com.bitzh.repository.MyClassRepository;import com.bitzh.repository.OrderRepository;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.InputStream;public class Test6 { public static void main (String[] args) { InputStream inputStream = Test2.class.getClassLoader().getResourceAsStream("config.xml" ); SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder (); SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); MyClassRepository myClassRepository = sqlSession.getMapper(MyClassRepository.class); MyClass myClass = myClassRepository.findById(1 ); System.out.println(myClass); sqlSession.close(); SqlSession sqlSession2 = sqlSessionFactory.openSession(); MyClassRepository myClassRepository2 = sqlSession2.getMapper(MyClassRepository.class); MyClass myClass2 = myClassRepository2.findById(1 ); System.out.println(myClass2); sqlSession.close(); } }
第三方ehcache二级缓存
1、pom.xml
1 2 3 4 5 6 7 8 9 10 11 <dependency > <groupId > net.sf.ehcache</groupId > <artifactId > ehcache-core</artifactId > <version > 2.4.3</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-ehcache</artifactId > <version > 1.0.0</version > </dependency >
2、resources路径下创建ehcache.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 <?xml version="1.0" encoding="UTF-8" ?> <ehcache xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation ="http://ehcache.org/ehcache.xsd" updateCheck ="false" > <diskStore /> <defaultCache eternal ="false" maxElementsInMemory ="10000" overflowToDisk ="false" diskPersistent ="false" timeToIdleSeconds ="1800" timeToLiveSeconds ="259200" memoryStoreEvictionPolicy ="LRU" /> </ehcache >
3、config.xml中配置二级缓存
1 2 <setting name ="cacheEnabled" value ="true" />
4、Mapper.xml中配置二级缓存。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?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" > <mapper namespace ="com.bitzh.repository.MyClassRepository" > <cache type ="org.mybatis.caches.ehcache.EhcacheCache" > <property name ="timeToIdleSeconds" value ="3600" /> <property name ="timeToLiveSeconds" value ="3600" /> <property name ="memoryStoreEvictionPolicy" value ="LRU" /> </cache > <select id ="findById" parameterType ="java.lang.Integer" resultType ="com.bitzh.entity.MyClass" > select * from t_classes where id =#{id} </select > </mapper >
5、实体类不需要实现序列化接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.bitzh.entity;import lombok.Data;import java.io.Serializable;@Data public class MyClass { private Integer id; private String name; }
6、测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package com.bitzh.test;import com.bitzh.entity.MyClass;import com.bitzh.repository.MyClassRepository;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.InputStream;public class Test6 { public static void main (String[] args) { InputStream inputStream = Test3.class.getClassLoader().getResourceAsStream("config.xml" ); SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder (); SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); MyClassRepository myClassRepository = sqlSession.getMapper(MyClassRepository.class); MyClass myClass = myClassRepository.findById(1 ); System.out.println(myClass); sqlSession = sqlSessionFactory.openSession(); myClassRepository = sqlSession.getMapper(MyClassRepository.class); MyClass myClass2 = myClassRepository.findById(1 ); System.out.println(myClass2); sqlSession.close(); } }
MyBatis动态SQL
通过id和username查询user
通过username和password查询user
通过password和age查询user
在userRepository中定义上述三个方法
UserRepository.xml
1 2 3 4 5 6 7 8 9 <select id ="findByUser1" parameterType ="User" resultType ="User" > select * from t_user where id = #{id} and username = #{username} </select > <select id ="findByUser2" parameterType ="User" resultType ="User" > select * from t_user where username = #{username} and password = #{password} </select > <select id ="findByUser3" parameterType ="User" resultType ="User" > select * from t_user where password = #{password} and username = #{username} </select >
这里很多冗余由于条件不同导致我们要写多次,这里我们想传入什么数据动态匹配条件
MyBatis动态SQL,SQL不像是固定的,可以根据不同的参数信息来动态凭借不同的SQL,以适应不同的需求。
1、创建实体类
1 2 3 4 5 6 7 @Data public class User { private Integer id; private String username; private String password; private Integer age; }
2、创建UserRepository(Mapper.java)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package com.bitzh.repository;import com.bitzh.entity.User;public interface UserRepository { public User findByUser1 (User user) ; public User findByUser2 (User user) ; public User findByUser3 (User user) ; }
3、Mapper.xml
1 2 3 4 5 6 7 8 9 <?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" > <mapper namespace ="com.bitzh.repository.UserRepository" > <select id ="findByUser" parameterType ="com.bitzh.entity.User" resultType ="com.bitzh.entity.User" > select * from t_user where id =#{id} and username = #{username} and password = #{password} and age = #{age} </select > </mapper >
4、config.xml中注册
1 <mapper resource ="com/bitzh/repository/UserRepository.xml" > </mapper >
5、测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package com.bitzh.test;import com.bitzh.entity.MyClass;import com.bitzh.entity.User;import com.bitzh.repository.MyClassRepository;import com.bitzh.repository.UserRepository;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.InputStream;public class Test7 { public static void main (String[] args) { InputStream inputStream = Test3.class.getClassLoader().getResourceAsStream("config.xml" ); SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder (); SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); UserRepository userRepository = sqlSession.getMapper(UserRepository.class); User user = new User (); user.setPassword("300" ); user.setUsername("李四" ); user.setAge(6 ); User user1 = userRepository.findByUser1(user); System.out.println(user1); } }
动态SQL
if
where where就是判断如果where和and中间什么都没就会自动删除and。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?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" > <mapper namespace ="com.bitzh.repository.UserRepository" > <select id ="findByUser1" parameterType ="com.bitzh.entity.User" resultType ="com.bitzh.entity.User" > select * from t_user <where > <if test ="id!=null" > id =#{id} </if > <if test ="username != null" > and username = #{username} </if > <if test ="password != null" > and password = #{password} </if > <if test ="age != null" > and age = #{age} </if > </where > </select > </mapper >
这个类似于switch case
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <?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" > <mapper namespace ="com.bitzh.repository.UserRepository" > <select id ="findByUser1" parameterType ="com.bitzh.entity.User" resultType ="com.bitzh.entity.User" > select * from t_user <where > <choose > <when test ="id!=null" > id =#{id} </when > <when test ="username != null" > and username = #{username} </when > <when test ="password != null" > and password = #{password} </when > <when test ="age != null" > and age = #{age} </when > </choose > </where > </select > </mapper >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?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" > <mapper namespace ="com.bitzh.repository.UserRepository" > <select id ="findByUser1" parameterType ="com.bitzh.entity.User" resultType ="com.bitzh.entity.User" > select * from t_user <trim prefix ="where" prefixOverrides ="and" > <if test ="id!=null" > id =#{id} </if > <if test ="username != null" > and username = #{username} </if > <if test ="password != null" > and password = #{password} </if > <if test ="age != null" > and age = #{age} </if > </trim > </select > </mapper >
set标签用于Update操作,会自动根据参数来选择生成sql语句。
mapper.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.bitzh.repository;import com.bitzh.entity.User;public interface UserRepository { public int update (User user) ; }
mapper.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <update id ="update" parameterType ="com.bitzh.entity.User" > update t_user <set > <if test ="username != null" > username = #{username} </if > <if test ="password != null" > ,password = #{password} </if > <if test ="age != null" > , age = #{age} </if > </set > where id = #{id} </update >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 package com.bitzh.test;import com.bitzh.entity.MyClass;import com.bitzh.entity.User;import com.bitzh.repository.MyClassRepository;import com.bitzh.repository.UserRepository;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.InputStream;public class Test7 { public static void main (String[] args) { InputStream inputStream = Test3.class.getClassLoader().getResourceAsStream("config.xml" ); SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder (); SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); UserRepository userRepository = sqlSession.getMapper(UserRepository.class); User user = new User (); user.setPassword("300" ); user.setUsername("李四" ); user.setAge(6 ); User user1 = userRepository.findByUser1(user); User user2 = new User (); user2.setId(2 ); user2.setUsername("tom" ); user2.setAge(18 ); userRepository.update(user2); sqlSession.commit(); } }