Mybatis的使用

1.MyBatis的简介

概述:和数据库进行交互,持久化层框架(SQL映射框架)

操作数据库的其他工具和框架:

1)从原始的JDBC--》dbUtils(QueryRunner)--》jdbcTemplate,以上这些都称为工具,工具是对一些功能的简单封装,而框架则是某个领域的整体解决方案:考虑缓存,考虑异常处理问题,考虑部分字段映射问题等等

2)Hibernate:数据库交互的框架(ORM框架,全自动框架 )

Mybatis

  • MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。

  • MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。

  • MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录.

为什么要使用MyBatis?

1.MyBatis是一个半自动化的持久化层框架。

2.JDBC

  • SQL夹在Java代码块里,耦合度高导致硬编码内伤

  • 维护不易且实际开发需求中sql是有变化,频繁修改的情况多见

3.Hibernate和JPA

  • 长、难、复杂SQL,对于Hibernate而言处理也不容易

  • 内部自动生产的SQL,不容易做特殊优化。

  • 基于全映射的全自动框架,大量字段的POJO进行部分映射时比较困难。导致数据库性能下降。

4.对开发人员而言,核心sql还是需要自己优化,
MyBatis框架中sql和java编码分开,功能边界清晰,一个专注业务、一个专注数据。

2.创建第一个MyBatis程序

创建第一个MyBatis的步骤:

1)导包:

  • mybatis-3.4.1.jar
  • mysql-connector-java-8.0.17.jar
  • log4j-1.2.17.jar(建议导入,这样在mybatis关键的环节就会有日志打印,依赖类路径下一个log4f.xml配置文件)

2)写配置(全局配置文件和dao接口的实现文件)

  • 第一个配置文件:成为mybatis的全局配置文件,知道mybatis如何正确运行,比如连接向哪个数据库
  • 第二个配置文件:编写的每一个方法都是如何向数据库发送sql语句,如何执行的,相当于接口的实现类
  • 我们写的dao接口的实现文件,MyBatis是不知道的,需要在全局配置文件中注册

3)测试

  • 根据全局配置文件先创建一个sqlSessionFactory
  • 从sqlSessionFactory中获取sqlSession对象操作数据库即可

代码实现:

环境部署:

数据库操作:

新建数据库(my):create database my;

新建User表:

create table user_01(
	id int not null auto_increment PRIMARY KEY,
	username VARCHAR(20),
	`PASSWORD` VARCHAR(20),
	role VARCHAR(20)
)

bean组件(User.java):

package com.luyi.bean;

public class User {
	private Integer id;
	private String username;
	private String password;
	private String role;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getRole() {
		return role;
	}
	public void setRole(String role) {
		this.role = role;
	}
	public String toString() {
		return "User [id=" + id + ", username=" + username + ", password="
				+ password + ", role=" + role + "]";
	}
	
}

dao层接口(UserDao.java)

package com.luyi.dao;

import com.luyi.bean.User;

public interface UserDao {
	public User getUser(int i);
}

写配置:

第一个配置文件(mybatis-config.xml):

<?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/my?serverTimezone=UTC"/>
        <property name="username" value="root"/>
        <property name="password" value="123"/>
      </dataSource>
    </environment>
  </environments>
  <!-- 引入我们自己编写的每一个接口实现文件 -->
  <mappers>
  <!-- resource:表示从类路径下找资源 -->
    <mapper resource="UserDao.xml"/>
  </mappers>
</configuration>

第二个配置文件(UserDao.xml):

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:名称空间,写接口的全类名,相当于告诉MyBatis这个配置文件是实现哪个接口的 -->
<mapper namespace="com.luyi.dao.UserDao">
<!-- select标签用来定义一个查询操作 -->
<!-- 
	id:用来定义方法名,相当于这个配置是对某个方法的实现
	resultType:指定方法运行后的返回值类型(查询操作必须指定)
 -->
  <select id="getUser" resultType="com.luyi.bean.User">
    select * from user where id = #{id}
  </select>
</mapper>

测试(MyBatisTest01.java文件):

package com.luyi.test;

import java.io.IOException;
import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import com.luyi.bean.User;
import com.luyi.dao.UserDao;

public class MyBatisTest01 {

	public static void main(String[] args) throws IOException {
		//根据全局配置文件创建一个SqlSessionFactory
		//sqlSessionFactory:是SqlSession工厂,负责创建SqlSession对象
		//sqlSession:sql会话(代表和数据库的一次会话)
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		
		User user = null;
		SqlSession openSession = null;
		try {
			//获取和数据库的一次会话:相当于getConnection()
			openSession = sqlSessionFactory.openSession();
			
			//使用sqlSession操作数据库,获取到dao接口的实现
			UserDao userDao = (UserDao) openSession.getMapper(UserDao.class);
			user = userDao.getUser(3);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			openSession.close();
		}
		System.out.println(user);
		
	}
}

补充:Mybatis导入dtd文件使得写xml文件时有提示

MyBatis的CRUD

在上面程序进行简单的修改:

User.java:

package com.luyi.bean;

public class User {
	private Integer id;
	private String username;
	private String password;
	private String role;
	
	public User(){};
	public User(Integer id, String username, String password, String role) {
		super();
		this.id = id;
		this.username = username;
		this.password = password;
		this.role = role;
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getRole() {
		return role;
	}
	public void setRole(String role) {
		this.role = role;
	}
	public String toString() {
		return "User [id=" + id + ", username=" + username + ", password="
				+ password + ", role=" + role + "]";
	}
	
}

UserDao.java

package com.luyi.dao;

import com.luyi.bean.User;

public interface UserDao {
	public User getUser(int i);
	public int updateUser(User user);
	public int deleteUser(int i);
	public int addUser(User user);
}

测试文件:

package com.luyi.test;

import java.io.IOException;
import java.io.InputStream;

import junit.framework.TestCase;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import com.luyi.bean.User;
import com.luyi.dao.UserDao;

public class Test01 extends TestCase {
	public SqlSessionFactory initSqlSessionFactory() throws IOException{
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		return sqlSessionFactory;
	}
	
	public void testSelect() throws IOException{
		SqlSession openSession = initSqlSessionFactory().openSession();
		UserDao userDao = openSession.getMapper(UserDao.class);
		
		try {
			User user = userDao.getUser(3);
			System.out.println(user);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			openSession.close();
		}
	}
	
	public void testUpdate() throws IOException{
		SqlSession openSession = initSqlSessionFactory().openSession();
		UserDao userDao = openSession.getMapper(UserDao.class);
		User user = new User(3, "luyi", "123", "student");
		
		try {
			int row = userDao.updateUser(user);
			System.out.println(row);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			openSession.commit();
			openSession.close();
		}
	}
	
	public void testDelete() throws IOException{
		SqlSession openSession = initSqlSessionFactory().openSession();
		UserDao userDao = openSession.getMapper(UserDao.class);
		
		try {
			int row = userDao.deleteUser(3);
			System.out.println(row);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			openSession.commit();
			openSession.close();
		}
	}
	
	public void testInsert() throws IOException{
		SqlSession openSession = initSqlSessionFactory().openSession();
		UserDao userDao = openSession.getMapper(UserDao.class);
		User user = new User(null, "天才", "77777", "student");
		
		try {
			int row = userDao.addUser(user);
			System.out.println(row);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			openSession.commit();
			openSession.close();
		}
	}
}

3.全局配置文件的配置

properties-引入外部配置文件

代码示例:

<?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属性引入properties配置文件 -->
<properties resource="dbconfig.properties"></properties>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driverclass}"/>
        <property name="url" value="${jdbcurl}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="UserDao.xml"/>
  </mappers>
</configuration>

settings-修改mybatis的运行时行为

比较常用的是设置是否开启驼峰命名映射:

<!-- 改变 MyBatis 的运行时行为 -->
<settings>
	<!-- 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。 -->
	<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

typeAliases-给java类型起别名

代码示例(推荐还是使用全类名):

<typeAliases>
	<!-- 默认起的别名是这个类名 -->
	<typeAlias type="com.luyi.bean.User" alias="User"/>
	<!-- 批量起别名,name指定包名 ,默认别名为这个类名
	批量起别名,如果也想自定义别名,就在那个要起别名的bean上面加个@Alias("别名")注解-->
	<package name="com.luyi.bean"/>
</typeAliases>

typeHandlers-类型处理器

概述:默认的类型处理器已经够我们的基本使用了,基本上不用再去注册自顶的类型处理器了

<typeHandlers>
	<typeHandler handler="自定义的类型处理器"/>
</typeHandlers>

plugins插件

概述:插件是MyBatis提供的一个非常强大的机制,我们可以通过插件来修改MyBatis的一些核心行为,插件通过动态代理机制,可以介入四大对象的任何一个方法的执行

  • Executor:执行器,负责执行sql语句
  • ParameterHandler:参数处理器,预编译搞好后,给预编译设置参数
  • ResultSetHandler:结果处理器
  • StatementHandler:用来预编译参数

environments-配置环境

代码示例:

<environments default="development">
    <environment id="development">
    <!-- JDBC – 这个配置就是直接使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务范围。 -->
      <transactionManager type="JDBC"/>
      <!-- 有三种内建的数据源类型(也就是 type=”[UNPOOLED|POOLED|JNDI]”) -->
      <dataSource type="POOLED">
        <property name="driver" value="${driverclass}"/>
        <property name="url" value="${jdbcurl}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
</environments>

databaseIdProvider-用于数据库移植

代码示例:

全局配置文件:

<databaseIdProvider type="DB_VENDOR">
	<property name="MySQL" value="mysql"/>
	<property name="SQL Server" value="sqlServer"/>
	<property name="Oracle" value="oracle"/>
</databaseIdProvider>

SQL映射文件:

<select id="getUser" resultType="User" databaseId="mysql">
	select * from user where id = #{id}
</select>

<select id="getUser" resultType="User" databaseId="oracle">
	select * from user where id = #{id}
</select>

<select id="getUser" resultType="User" >
	select * from user where id = #{id}
</select>

mappers-映射器

注册单个(代码示例):

<mappers>
  	<!-- 
  		url:可以从磁盘或者网络路径引用
  		resource:在类路径下找sql映射文件
  		class:直接引用接口的全类名;可以将xml放在和dao接口同目录下,而且文件名和接口名一致
  		class的另一种用法:把select,update,delete,insert标签里的sql语句通过注解直接写在dao文件对应的方法上,那么我们的class也只能是写这个有注解的类的全类名了
  	 -->
    
    <mapper class="com.luyi.dao.UserDao"/>
</mappers>

批量注册:

注意:批量注册这里的所有dao接口文件以及SQL映射配置文件都得放在com.luyi.dao包下才会注册成功,为了比较规范好看,我们可以在conf文件夹下重新新建一个也叫做com.luyi.dao的package

4.SQL映射文件

这个文件中的所有标签:

  • cache:和缓存有关
  • cache-ref:和缓存有关
  • parameterMap:参数map,废弃的,原本是用来做复制参数映射
  • insert,delete,upate,select
  • sql:抽取1可重用的sql

insert,delete,upate,select里的属性

获取自增主键的值代码示例:

<!-- 
	useGeneratedKeys="true":原生jdbc获取自增主键的方法
	keyProperty="":将刚才自增的id封装给哪个属性
-->
<insert id="addUser" useGeneratedKeys="true" keyProperty="id">
	insert into user(username, password, role) values(#{username}, #{password}, #{role})
</insert>

<!--再在测试文件中直接获取这个id的值是可以获取得到的-->

获取非自增主键的值的代码示例:

<insert id="addUser">
	<!-- order="BEFORE":在核心sql语句之前先运行一个查询sql查到id,将查到的id赋值给javaBean的id属性 -->
	<selectKey order="BEFORE" resultType="Integer" keyProperty="id">
	select max(id) + 1 from user  		
	</selectKey>
	insert into user(username, password, role) values(#{username}, #{password}, #{role})
</insert>

SQL映射文件中参数传递

  • 单个参数:

    • 基本类型:取值的方法为:#
  • 多个参数

    • 取值时通过#{参数名}是取不出来的
    • 只能通过0,1(参数的索引)或者param1,param2(第几个参数)获取参数值
    • 原因是只要传入了多个参数,mybatis会自动的将这些参数封装在一个map中,封装时使用的key就是参数的索引和参数的第几个表示
  • 为参数指定key,命名参数,通过@Param注解实现,这是我们推荐的写法,我们可以告诉mybatis,封装参数map的时候别乱来,使用我们指定的key

  • 传入map:直接使用#{key}取出

  • 传入pojo:取出参数的方法为:#

参数处理

参数也可以指定一个特殊的数据类型:

  • javaType 通常可以从参数对象中来去确定
  • 如果 null 被当作值来传递,对于所有可能为空的列,jdbcType 需要被设置,原因是null值对于oracle数据库是不认识的,会导致报错(常用设置)
  • 对于数值类型,还可以设置小数点后保留的位数:
  • mode 属性允许指定 IN,OUT 或 INOUT 参数。如果参数为 OUT 或 INOUT,参数对象属性的真实值将会被改变,就像在获取输出参数时所期望的那样。
  • 参数位置支持的属性:
    javaType、jdbcType、mode、numericScale、
    resultMap、typeHandler、jdbcTypeName、expression

#{key}与${key}的区别

  • #{key}:获取参数的值,预编译到SQL中。安全。
  • ${key}:获取参数的值,拼接到SQL中。有SQL注入问题。ORDER BY ${name};${key}还可以用于不是参数的位置,如${user}(表名),而#{key}则不行

查询结果返回list

代码示例:

SQL映射文件:

...
<select id="getAll" resultType="com.luyi.bean.User">
  	select * from user
</select>
...

UserDao.java:

public List<User> getAll();

Test.java:

public void testSelect() throws IOException{
		SqlSession openSession = initSqlSessionFactory().openSession();
		UserDao userDao = openSession.getMapper(UserDao.class);
		
		try {
			List<User> list = userDao.getAll();
			
			for(User user:list){
				System.out.println(user);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			openSession.close();
		}
	}

查询结果返回map

查询单条封装成map代码示例:

UserDao.xml:

<select id="getAllReturnMap" resultType="map">
  	select * from user where id = #{id}
</select>

UserDao.java:

public Map<String, Object> getAllReturnMap(int i);

Test.java:

public void testSelectReturnMap() throws IOException{
		SqlSession openSession = initSqlSessionFactory().openSession();
		UserDao userDao = openSession.getMapper(UserDao.class);
		
		try {
			Map<String, Object> map = userDao.getAllReturnMap(6);
			System.out.println(map);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			openSession.close();
		}
	}

查询多条返回Map代码示例:

UserDao.java:

//注解标志id为map的key
@MapKey("id")
public Map<Integer, User> getAllReturnMaps();

UserDao.xml:

<select id="getAllReturnMaps" resultType="com.luyi.bean.User">
	select * from user 
</select>

Test.java:

public void testSelectReturnMaps() throws IOException{
		SqlSession openSession = initSqlSessionFactory().openSession();
		UserDao userDao = openSession.getMapper(UserDao.class);
		
		try {
			Map<Integer, User> map = userDao.getAllReturnMaps();
			
			System.out.println(map);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			openSession.close();
		}
	}

自定义映射规则,自己定义每一列数据和javaBean的映射规则

默认的映射规则(mybatis自动封装结果集的规则):

  • 按照列名和属性名一一对应的规则(不区分大小写)
  • 如果不一一对应
    • 开启驼峰命名法:满足驼峰命名规则的一一对应
    • 起别名

自定义映射规则:

SQL映射文件:

...
<select id="getAll" resultMap="myUser">
	select * from user
</select>
<!--type:指定为哪个javaBean自定义封装规则,id=“”:唯一标识,让别名在后面给引用-->
<resultMap type="com.luyi.bean.User" id="myUser">
	<id property="id" column="id"/>
	<result property="username" column="name"/>
	<result property="password" column="pw"/>
	<result property="role" column="role"/>
</resultMap>

联合查询(1对1)

环境搭建(数据库表的数据):

key表:

lock表:

代码实现(使用了if标签:OGNL表达式):

所有的bean文件:

//Key.java
package com.luyi.bean;

public class Key {
	private Integer id;
	private String keyName;
	private Lock lock;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getKeyName() {
		return keyName;
	}
	public void setKeyName(String keyName) {
		this.keyName = keyName;
	}
	public Lock getLock() {
		return lock;
	}
	public void setLock(Lock lock) {
		this.lock = lock;
	}
	public String toString() {
		return "Key [id=" + id + ", keyName=" + keyName + ", lock=" + lock
				+ "]";
	}
	
}

//Lock.java
package com.luyi.bean;

public class Lock {
	private Integer id;
	private String lockName;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getLockName() {
		return lockName;
	}
	public void setLockName(String lockName) {
		this.lockName = lockName;
	}
	public String toString() {
		return "Lock [id=" + id + ", lockName=" + lockName + "]";
	}
	
}

dao文件:

//KeyDao.java
package com.luyi.dao;

import com.luyi.bean.Key;

public interface KeyDao {
	public Key getKeyById(int id);
}

SQL映射配置文件:

<!--KeyDao.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.luyi.dao.KeyDao">
  <select id="getKeyById" resultMap="mykey">
    select k.id kid, k.keyName, k.lockId, l.id lid, l.lockName
      from `key` k 
      LEFT JOIN `LOCK` l ON 
      k.lockId = l.id where k.id = #{id}  
  </select>
  <!-- 自定义封装规则:方式一:级联属性封装查出的数据 -->
  <resultMap type="com.luyi.bean.Key" id="mykey">
  	<id property="id" column="kid"/>
  	<result property="keyName" column="keyName"/>
  	<result property="lock.id" column="lid"/>
  	<result property="lock.lockName" column="lockName"/>
  </resultMap>


  <!-- 自定义封装规则:方式二:association定义联合查询的对象 -->
<resultMap type="com.luyi.bean.Key" id="mykey">
  	<id property="id" column="kid"/>
  	<result property="keyName" column="keyName"/>
  	<!-- 接下来的属性是一个对象,自定义这个对象分封装规则,使用association:表示联合了一个对象 -->
  	<!-- javaType:指定这个属性的类型 -->
  	<association property="lock" javaType="com.luyi.bean.Lock">
  		<result property="id" column="lid"/>
  		<result property="lockName" column="lockName"/>
  	</association>
</resultMap>



</mapper>

properties文件(dbconfig):

username=root
password=123
jdbcurl=jdbc:mysql://localhost:3306/my?serverTimezone=UTC
driverclass=com.mysql.cj.jdbc.Driver

全局配置文件:

<!--mybatis-config.xml-->
<?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="dbconfig.properties"></properties>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <!--properties属性引入properties配置文件 -->
      <dataSource type="POOLED">
        <property name="driver" value="${driverclass}"/>
        <property name="url" value="${jdbcurl}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="KeyDao.xml"/>
  </mappers>
</configuration>

测试文件(Test01.java):

package com.luyi.test;

import java.io.IOException;
import java.io.InputStream;

import junit.framework.TestCase;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import com.luyi.bean.Key;
import com.luyi.dao.KeyDao;

public class Test01 extends TestCase {
	public SqlSessionFactory initSqlSessionFactory() throws IOException{
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		return sqlSessionFactory;
	}
	public void test01() throws IOException{
		SqlSession openSession = initSqlSessionFactory().openSession();
		try {
			KeyDao mapper = (KeyDao) openSession.getMapper(KeyDao.class);
			Key key = mapper.getKeyById(1);
			System.out.println(key);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			openSession.close();
		}
	}
}

联合查询(1对多)

在联合查询(1对1)的代码实现基础上进行一下修改:

Lock.java:

package com.luyi.bean;

import java.util.List;


public class Lock {
	private Integer id;
	private String lockName;
	private List<Key> keys;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getLockName() {
		return lockName;
	}
	public void setLockName(String lockName) {
		this.lockName = lockName;
	}
	
	public List<Key> getKeys() {
		return keys;
	}
	public void setKeys(List<Key> keys) {
		this.keys = keys;
	}
	@Override
	public String toString() {
		return "Lock [id=" + id + ", lockName=" + lockName + ", keys=" + keys
				+ "]";
	}
}

LockDao.java:

package com.luyi.dao;

import com.luyi.bean.Lock;

public interface LockDao {

	//查询锁时把所有的钥匙也查询出来
	public Lock getLockById(int id);
}

LockDao.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.luyi.dao.LockDao">
  <select id="getLockById" resultMap="myLock">
    select k.id kid, k.keyName, k.lockId, l.id lid, l.lockName
      from `key` k 
      LEFT JOIN `LOCK` l ON 
      k.lockId = l.id where l.id = #{id}  
  </select>
  <!-- 自定义封装规则,collection标签定义集合类型分封装 -->
  <resultMap type="com.luyi.bean.Lock" id="myLock">
  	<id property="id" column="lid"/>
  	<result property="lockName" column="lockName"/>
  	<!-- collection:定义集合元素的封装
  	propertype="":指定哪个属性是集合属性
  	ofType="":指定集合里面元素的类型 -->
  	<collection property="keys" ofType="com.luyi.bean.Key">
  		<!-- 标签体中指定集合中这个元素的封装规则 -->
  		<id property="id" column="kid"/>
  		<result property="keyName" column="keyName"/>
  	</collection>
  </resultMap>
</mapper>

测试文件:Test01.java:

package com.luyi.test;

import java.io.IOException;
import java.io.InputStream;

import junit.framework.TestCase;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import com.luyi.bean.Key;
import com.luyi.bean.Lock;
import com.luyi.dao.KeyDao;
import com.luyi.dao.LockDao;

public class Test01 extends TestCase {
	public SqlSessionFactory initSqlSessionFactory() throws IOException{
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		return sqlSessionFactory;
	}
	
	public void test02() throws IOException{
		SqlSession openSession = initSqlSessionFactory().openSession();
		try {
			LockDao mapper =  openSession.getMapper(LockDao.class);
			Lock lock = mapper.getLockById(3);
			System.out.println(lock);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			openSession.close();
		}
	}
}

联合查询(association分步查询)

代码实现(在联合查询(1对多)的代码实现上进行修改):

KeyDao.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.luyi.dao.KeyDao">
  <select id="getKeyById" resultMap="mykey">
      select * from `key` where id = #{id}
  </select>
  <!-- 自定义封装规则,association定义联合查询的对象 -->
  <resultMap type="com.luyi.bean.Key" id="mykey">
  	<id property="id" column="kid"/>
  	<result property="keyName" column="keyName"/>
  	<!-- 告诉mybatis自己去调用一个查询查询锁
  	select="":指定一个查询sql的唯一标识,mybatis自动调用指定的sql将查出的lock封装进来
  	column:指定将哪一列的数据传递过去
  	 -->
  	<association property="lock" 
  	select="com.luyi.dao.LockDao.getLockById"
  	column="id"
  	 >
  	</association>
  </resultMap>
</mapper>

LockDao.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.luyi.dao.LockDao">
  <select id="getLockById" resultType="com.luyi.bean.Lock" > 
      select * from `lock` where id = #{id}
  </select>

</mapper>

注意:测试方法使用的是test01方法测试;

联合查询(按需加载和延迟加载)

按需加载的配置:

<settings>
	<!-- 开启延迟加载 -->
	<setting name="lazyLoadingEnabled" value="true"/>
	<!-- 开启属性按需加载 -->
	<setting name="aggressiveLazyLoading" value="false"/>
</settings>

注意:设置了按需加载的配置之后,使用分步查询时,不会马上两条查询语句都发出去,而是按需加载,当我们需要使用另一个bean的属性时,才发送查询语句过去查询获取这个属性

联合查询(collection分步查询延迟加载):

代码实现:

所有的bean文件:

//Key.java

package com.luyi.bean;

public class Key {
	private Integer id;
	private String keyName;
	private Lock lock;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getKeyName() {
		return keyName;
	}
	public void setKeyName(String keyName) {
		this.keyName = keyName;
	}
	public Lock getLock() {
		return lock;
	}
	public void setLock(Lock lock) {
		this.lock = lock;
	}
	public String toString() {
		return "Key [id=" + id + ", keyName=" + keyName + ", lock=" + lock
				+ "]";
	}
	
}

//Lock.java

package com.luyi.bean;

import java.util.List;


public class Lock {
	private Integer id;
	private String lockName;
	private List<Key> keys;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getLockName() {
		return lockName;
	}
	public void setLockName(String lockName) {
		this.lockName = lockName;
	}
	
	public List<Key> getKeys() {
		return keys;
	}
	public void setKeys(List<Key> keys) {
		this.keys = keys;
	}
	@Override
	public String toString() {
		return "Lock [id=" + id + ", lockName=" + lockName + ", keys=" + keys
				+ "]";
	}
}

所有的dao文件:

//KeyDao.java
package com.luyi.dao;

import java.util.List;

import com.luyi.bean.Key;

public interface KeyDao {
	public Key getKeyById(int id);
	public List<Key> getKeyByLockId(int id);
}

//LockDao.java

package com.luyi.dao;

import com.luyi.bean.Lock;

public interface LockDao {

	//查询锁时把所有的钥匙也查询出来
	public Lock getLockById(int id);
}

配置文件:

dbconfig.properties:

username=root
password=123
jdbcurl=jdbc:mysql://localhost:3306/my?serverTimezone=UTC
driverclass=com.mysql.cj.jdbc.Driver

mybatis-config.xml:

<?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="dbconfig.properties"></properties>
  <settings>
		<!-- 开启延迟加载 -->
		<setting name="lazyLoadingEnabled" value="true"/>
		<!-- 开启属性按需加载 -->
		<setting name="aggressiveLazyLoading" value="false"/>
	</settings>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <!--properties属性引入properties配置文件 -->
      <dataSource type="POOLED">
        <property name="driver" value="${driverclass}"/>
        <property name="url" value="${jdbcurl}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="KeyDao.xml"/>
    <mapper resource="LockDao.xml"/>
  </mappers>
</configuration>

log4j.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
 
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
 
 <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
   <param name="Encoding" value="UTF-8" />
   <layout class="org.apache.log4j.PatternLayout">
    <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m  (%F:%L) \n" />
   </layout>
 </appender>
 <logger name="java.sql">
   <level value="debug" />
 </logger>
 <logger name="org.apache.ibatis">
   <level value="info" />
 </logger>
 <root>
   <level value="debug" />
   <appender-ref ref="STDOUT" />
 </root>
</log4j:configuration>

KeyDao.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.luyi.dao.KeyDao">
	
  <select id="getKeyByLockId" resultType="com.luyi.bean.Key">
  	select * from `key` where lockId = #{id}
  </select>
  <select id="getKeyById" resultMap="mykey">
      select * from `key` where id = #{id}
  </select>
  <!-- 自定义封装规则,association定义联合查询的对象 -->
  <resultMap type="com.luyi.bean.Key" id="mykey">
  	<id property="id" column="kid"/>
  	<result property="keyName" column="keyName"/>
  	<!-- 告诉mybatis自己去调用一个查询查询锁
  	select="":指定一个查询sql的唯一标识,mybatis自动调用指定的sql将查出的lock封装进来
  	column:指定将哪一列的数据传递过去
  	 -->
  	<association property="lock" 
  	select="com.luyi.dao.LockDao.getLockById"
  	column="id"
  	 >
  	</association>
  </resultMap>
</mapper>

LockDao.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.luyi.dao.LockDao">
  <select id="getLockById" resultMap="myLock"  > 
      select * from `lock` where id = #{id}
  </select>
  <!-- collection分布查询 -->
  <resultMap type="com.luyi.bean.Lock" id="myLock">
  	<id property="id" column="id"/>
  	<result property="lockName" column="lockName"/>
  	<collection property="keys" 
  	select="com.luyi.dao.KeyDao.getKeyByLockId"
  	column="id">
  		
  	</collection>
  </resultMap>
  
</mapper>

测试文件(Test01.java):

package com.luyi.test;

import java.io.IOException;
import java.io.InputStream;

import junit.framework.TestCase;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import com.luyi.bean.Key;
import com.luyi.bean.Lock;
import com.luyi.dao.KeyDao;
import com.luyi.dao.LockDao;

public class Test01 extends TestCase {
	public SqlSessionFactory initSqlSessionFactory() throws IOException{
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		return sqlSessionFactory;
	}
	public void test01() throws IOException{
		SqlSession openSession = initSqlSessionFactory().openSession();
		try {
			KeyDao mapper = (KeyDao) openSession.getMapper(KeyDao.class);
			Key key = mapper.getKeyById(1);
			System.out.println(key.getLock().getLockName());
			Thread.sleep(3000);
			System.out.println(key.getKeyName());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			openSession.close();
		}
	}
	
	public void test02() throws IOException{
		SqlSession openSession = initSqlSessionFactory().openSession();
		try {
			LockDao mapper =  openSession.getMapper(LockDao.class);
			Lock lock = mapper.getLockById(3);
			System.out.println(lock.getLockName());
			System.out.println(lock.getKeys());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			openSession.close();
		}
	}
}

6.动态sql

概述:方便了我们拼接数据库表字符

第一个动态sql程序:

环境部署:

代码实现:

bean文件:

//Teacher.java
package com.luyi.bean;

import java.util.Date;

public class Teacher {
	private Integer id;
	private String teacherName;
	private String address;
	private Date birth;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getTeacherName() {
		return teacherName;
	}
	public void setTeacherName(String teacherName) {
		this.teacherName = teacherName;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public Date getBirth() {
		return birth;
	}
	public void setBirth(Date birth) {
		this.birth = birth;
	}
	@Override
	public String toString() {
		return "Teacher [id=" + id + ", teacherName=" + teacherName
				+ ", address=" + address + ", birth=" + birth + "]";
	}
	
	
}

dao文件:

//TeacherDao.java
package com.luyi.dao;

import com.luyi.bean.Teacher;

public interface TeacherDao {
	public Teacher getTeacherByCondition(Teacher teacher);
}

SQL映射文件(TeacherDao.xml):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.luyi.dao.TeacherDao">
  <select id="getTeacherByCondition" resultType="com.luyi.bean.Teacher">
    select * from Teacher where
    <!-- if标签判断条件进行sql拼接 -->
    <if test="id!=null">
    	id > #{id} 
    </if>
    <if test="teacherName != null and teacherName != ''">
    	and teacherName like #{teacherName}
    </if>
    <if test="birth != null">
    	and birth &lt; #{birth}
    </if>
  </select>
</mapper>

dbconfig.properties:

username=root
password=123
jdbcurl=jdbc:mysql://localhost:3306/my?serverTimezone=UTC
driverclass=com.mysql.cj.jdbc.Driver

mybtais-config.xml:

<?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="dbconfig.properties"></properties>
  <settings>
		<!-- 开启延迟加载 -->
		<setting name="lazyLoadingEnabled" value="true"/>
		<!-- 开启属性按需加载 -->
		<setting name="aggressiveLazyLoading" value="false"/>
	</settings>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <!--properties属性引入properties配置文件 -->
      <dataSource type="POOLED">
        <property name="driver" value="${driverclass}"/>
        <property name="url" value="${jdbcurl}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="TeacherDao.xml"/>
  </mappers>
</configuration>

测试文件(Test01.java):

package com.luyi.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;

import junit.framework.TestCase;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import com.luyi.bean.Teacher;
import com.luyi.dao.TeacherDao;

public class Test01 extends TestCase {
	public SqlSessionFactory initSqlSessionFactory() throws IOException{
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		return sqlSessionFactory;
	} 
	public void test01() throws IOException{
		SqlSession openSession = initSqlSessionFactory().openSession();
		try {
			TeacherDao teacherDao = openSession.getMapper(TeacherDao.class);
			Teacher teacher = new Teacher();
			teacher.setId(1);
			teacher.setTeacherName("赵%%");
			teacher.setBirth(new Date());
			System.out.println(teacher);
			Teacher result = teacherDao.getTeacherByCondition(teacher);
			System.out.println(result);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			openSession.close();
		}
	}
}

补充:where标签可以替代where关键字,帮我们去除写在前面的and,防止报错,如:

 <select id="getTeacherByCondition" resultType="com.luyi.bean.Teacher">
    select * from Teacher 
   <where>
   	 <!-- if标签判断条件进行sql拼接 -->
    <if test="id!=null">
    	and id > #{id} 
    </if>
    <if test="teacherName != null and teacherName != ''">
    	and teacherName like #{teacherName} 
    </if>
    <if test="birth != null">
    	and birth &lt; #{birth} 
    </if>
   </where>
  </select>

trim标签的使用:

trim截取字符串:

  • prefix="":前缀,为我们下面的sql整体添加一个前缀
  • prefixOverrides="" :取出整体字符串前面多余的字符
  • suffix="":为整体添加一个后缀
  • suffixOverrides="":后面哪个多了可以去掉

代码示例:

  <select id="getTeacherByCondition" resultType="com.luyi.bean.Teacher">
    select * from Teacher 
    <!-- trim截取字符串:
    	 prefix="":前缀,为我们下面的sql整体添加一个前缀
    	 prefixOverrides="" :取出整体字符串前面多余的字符
    	 suffix="":为整体添加一个后缀
    	 suffixOverrides="":后面哪个多了可以去掉
     -->
  	<trim prefix="where" prefixOverrides="and"  suffixOverrides="and">
	 	<!-- if标签判断条件进行sql拼接 -->
	    <if test="id!=null">
	    	and id > #{id} 
	    </if>
	    <if test="teacherName != null and teacherName != ''">
	    	and teacherName like #{teacherName} 
	    </if>
	    <if test="birth != null">
	    	and birth &lt; #{birth} 
	    </if>
  	</trim>
  </select>

foreach标签的使用

foreach标签遍历集合:

  • collection="":指定要遍历的集合的key
  • close="":以什么作为结束符号
  • index="i" :索引,
    • 如果遍历的是一个list:index,指定的变量保存当前索引;
    • 如果遍历的是一个map,index指定的变量就是保存了当前遍历的key
  • item="变量名":每次遍历出的元素起一个变量名方便引用
  • open="":以什么作为开始符号
  • separator="":每次遍历的元素的分隔符

代码示例(在动态sql的第一个程序案例的基础上进行修改):

TeacherDao.java:

package com.luyi.dao;



import java.util.List;

import org.apache.ibatis.annotations.Param;

import com.luyi.bean.Teacher;

public interface TeacherDao {
	public Teacher getTeacherByCondition(Teacher teacher);
	public List<Teacher> getTeachersByids(@Param("ids")List<Integer> ids);
}

TeacherDao.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.luyi.dao.TeacherDao">
  <select id="getTeacherByCondition" resultType="com.luyi.bean.Teacher">
    select * from Teacher 
    <!-- trim截取字符串:
    	 prefix="":前缀,为我们下面的sql整体添加一个前缀
    	 prefixOverrides="" :取出整体字符串前面多余的字符
    	 suffix="":为整体添加一个后缀
    	 suffixOverrides="":后面哪个多了可以去掉
     -->
  	<trim prefix="where" prefixOverrides="and"  suffixOverrides="and">
	 	<!-- if标签判断条件进行sql拼接 -->
	    <if test="id!=null">
	    	and id > #{id} 
	    </if>
	    <if test="teacherName != null and teacherName != ''">
	    	and teacherName like #{teacherName} 
	    </if>
	    <if test="birth != null">
	    	and birth &lt; #{birth} 
	    </if>
  	</trim>
  </select>

  <select id="getTeachersByids" resultType="com.luyi.bean.Teacher">
  	select * from teacher where id in 
  	<!-- 
  		 collection="":指定要遍历的集合的key 
  		 close="":以什么作为结束符号
 		 index="i" :索引,
 		 如果遍历的是一个list:index,指定的变量保存当前索引;
 		 如果遍历的是一个map,index指定的变量就是保存了当前遍历的key
 		 item="变量名":每次遍历出的元素起一个变量名方便引用
 		 open="":以什么作为开始符号
 		 separator="":每次遍历的元素的分隔符
  	 -->
  	<foreach collection="ids" close=")" index="" item="id_item" open="(" separator=",">
  		#{id_item}
  	</foreach>
  </select>

</mapper>

Test01.java:

package com.luyi.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import junit.framework.TestCase;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import com.luyi.bean.Teacher;
import com.luyi.dao.TeacherDao;

public class Test01 extends TestCase {
	public SqlSessionFactory initSqlSessionFactory() throws IOException{
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		return sqlSessionFactory;
	} 
	/**
	 * 测试第一个动态sql程序
	 * @throws IOException
	 */
	public void test01() throws IOException{
		SqlSession openSession = initSqlSessionFactory().openSession();
		try {
			TeacherDao teacherDao = openSession.getMapper(TeacherDao.class);
			Teacher teacher = new Teacher();
			teacher.setId(1);
			//teacher.setTeacherName("赵%%");
			teacher.setBirth(new Date());
			System.out.println(teacher);
			Teacher result = teacherDao.getTeacherByCondition(teacher);
			System.out.println(result);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			openSession.close();
		}
	}
	
	/**
	 * 测试foreach标签的使用
	 * @throws IOException
	 */
	public void test02() throws IOException{
		SqlSession openSession = initSqlSessionFactory().openSession();
		try {
			TeacherDao teacherDao = openSession.getMapper(TeacherDao.class);
			List<Integer> list = Arrays.asList(1, 2, 3);
			List<Teacher> result = teacherDao.getTeachersByids(list);
			System.out.println(result);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			openSession.close();
		}
	}
}

choose标签的使用

概述:choose标签中当when条件满足时,就不会往下走了

代码实现:

<trim prefix="where" prefixOverrides="and"  suffixOverrides="and">
	<choose>
		<when test="id != null">
			id=#{id} and
		</when>
		<when test="teacherName != null and teacherName != ''">
			teacherName like teacherName and
		</when>
		<when test="birth != null">
			birth &lt; #{birth}
		</when>
		<otherwise>
			1=1
		</otherwise>
	</choose>
</trim>

set标签结合if标签完成mybatis动态更新

概述:set替代了set关键字,并可以去除多余的逗号

代码实现:

<select id="updateTeacher" resultType="com.luyi.bean.Teacher">
	UPDATE teacher 
	<!-- set替代了set关键字,并可以去除多余的逗号 -->
	<set>
		<if test="teacherName != null and teacherName != ''">
			teacherName=#{teacherName},
		</if>
		<if test="address != null and address != ''">
			address = #{address},
		</if>
		<if test="birth != null">
			birth = #{birth},
		</if>
	</set>
	where id = #{id}
</select>

其他标签

1.bind标签:把一个表达式绑定到一个变量上

2.sql标签:抽取出可重用的sql语句

OGNL的介绍

OGNL(Object Graph Navigation Language),也就是对象导航图语言,这是一种强大的
表达式语言,通过它可以非常方便的来操作对象属性,使用方法就是级联属性一级一级往下调用即可

其他两个参数:

概述:在mybatis中,传入的参数可以用来做判断,额外还有两个参数_parameter和_databaseId

  • _parameter:代表传进来的参数

    • 传入了单个参数,_parameter就代表这个参数
    • 传入了多个参数,_parameter就代表多个参数集合起来的map
  • _databaseId:代表当前环境,如果配置了databaseIdProvider,_databaseId就有值

7.缓存机制(用Map保存查询出来的一些数据)

概述:MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存可以极大的提升查询效率。

MyBatis系统中默认定义了两级缓存(一级缓存和二级缓存):

  • 默认情况下,只有一级缓存(SqlSession级别的缓存,也称为本地缓存)开启。
  • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
  • 为了提高扩展性。MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

一级缓存(默认存在)

概述:只要之前查询过的数据,mybatis就会保存在一个缓存中(Map);下次获取直接从缓存中拿,需要注意的是一级缓存是sqlSession级别的缓存,sqlSession关闭或者提交以后,一级缓存的数据就会放在二级缓存中

一级缓存失效的几种情况:

1.不同的sqlSession使用不同的一级缓存

  • 只有在同一个sqlSession期间查询到的数据会保存在这个sqlSession的缓存中,下次使用这个sqlSession查询会从缓存中拿

2.同一个方法,不同的参数,由于可能之前没查询过,所以还会发新的sql

3.在这个sqlSession期间,如果有增删改操作,就会清空之前的缓存

4.手动清空缓存:通过openSession.clearCache()方法清空

二级缓存

概述:全局作用域缓存,二级缓存默认不启动,需要手动配置,MyBatis提供二级缓存的接口以及实现,缓存实现要求POJO实现Serializable接口,二级缓存在sqlSession关闭或提交之后才生效;二级缓存是namespace级别的缓存,说它是namespace级别的缓存是因为使用二级缓存的映射文件处需要使用chache标签进行配置,而这个映射文件映射的就是namespace指定的类

步骤:

  • 全局配置文件中开启二级缓存:<setting name="cacheEnabled" value="true"/>

  • 需要使用二级缓存的映射文件处使用cache配置缓存:<cache><cache/>

  • POJO需要实现Serializable接口

缓存的相关属性(了解)

概述:缓存的相关属性,也就是cache标签里面的属性

  • eviction=“FIFO”:缓存回收策略:
    LRU – 最近最少使用的:移除最长时间不被使用的对象。
  • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
  • WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
    默认的是 LRU。
  • flushInterval:刷新间隔,单位毫秒
    默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
  • size:引用数目,正整数
    代表缓存最多可以存储多少个对象,太大容易导致内存溢出
  • readOnly:只读,true/false
    true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
    false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。

缓存的查询顺序

1.不会出现一级缓存和二级缓存中有同一个数据

  • 二级缓存中,一级缓存关闭了就有了
  • 一级缓存中,二级缓存中没有此数据,就会看一级缓存,一级缓存没有去查数据库,数据库的查询后的结果放在一级缓存中

2.任何时候都是先看二级缓存,再看一级缓存,都没有,再去数据库查询

缓存有关设置

  • 全局setting的cacheEnable:
    配置二级缓存的开关。一级缓存一直是打开的。
  • select标签的useCache属性:
    配置这个select是否使用二级缓存。一级缓存一直是使用的
  • sql标签的flushCache属性:
    增删改默认flushCache=true。sql执行以后,会同时清空一级和二级缓存。查询默认flushCache=false。
  • sqlSession.clearCache():
    只是用来清除一级缓存。
  • 当在某一个作用域 (一级缓存Session/二级缓存Namespaces) 进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。

整合第三方缓存

概述:MyBatis自带的缓存的功能没有很强大,往往需要整合进其他一些优秀的缓存来进行MyBatis缓存的使用,我们可以通过Cache接口实现整合第三方缓存

下面我们通过整个EhCache来介绍整合第三方缓存的步骤:

EhCache概述:EhCache是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvide

MyBatis定义了Cache接口方便我们进行自定义扩展。
步骤:

  • 导入ehcache包,以及整合包,日志包
    ehcache-core-2.6.8.jar、mybatis-ehcache-1.0.3.jar
    slf4j-api-1.6.1.jar、slf4j-log4j12-1.6.2.jar
  • 编写ehcache.xml配置文件
  • 配置cache标签
  • 参照缓存:若想在命名空间中共享相同的缓存配置和实例。可以使用 cache-ref 元素来引用另外一个缓存。
posted @ 2020-09-08 10:39  luyi001  阅读(208)  评论(0编辑  收藏  举报