Mybatis框架-02


目录
  • Mybatis框架-02
    • 动态SQL
    • 多对一
      • 实体类
      • N+1策略
      • 等值策略
    • 一对多
      • 实体类
      • N+1策略
      • 等值策略
    • 缓存
      • 一级缓存
      • 二级缓存
    • 逆向工程

Mybatis框架-02

动态SQL

什么是动态sql?

可根据传进来的值不同,动态的生成sql语句。调用的是同一条sql语句,从而达到sql语句的复用。

比如说我要修改密码,sql语句只能修改密码,其他的不能修改我的。当我需要修改其他的东西的时候,调用的还是这条sql语句。他会动态的根据你的需要给你生成对应的sql语句。

xml方式

<?xml version="1.0" encoding="UTF-8"?>


  
    
    
    
    
        update user 
        
        
            name = #{name},
            password = #{password},
            age = #{age},
        
        where id = #{id}
    
    
    
    
    
    
      
        
            name like concat('%',#{name},'%')
            and age = #{age}
        
    
    
    
    
    
    
    
    
        delete from user where id in
        
            #{id}
        
    
    
    
    
        insert into user (name,password,age) values
        
            (#{user.name},#{user.password},#{user.age})
        
    
  

注解方式:标签不是原来的那套标签了

@UpdateProvider:type是你放在一个java类中完成,method是调用所对应的方法。

@UpdateProvider(type = UserSqlProvider.class,method = "update")
	int update(User user);
	
	@SelectProvider(type = UserSqlProvider.class, method = "selectListByCondition")
	List selectListByCondition(User user);
	
	@DeleteProvider(type = UserSqlProvider.class, method = "deleteByIds")
	int deleteByIds(@Param("ids") Integer[] ids);
	
	@InsertProvider(type = UserSqlProvider.class, method = "insertByBatch")
	int insertByBatch(@Param("users") List users);

需要创建一个SQL对象,或者是自己拼接sql语句,返回一个String

package cn.zj.mybatis.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.jdbc.SQL;

import cn.zj.mybatis.pojo.User;

public class UserSqlProvider {
	
	public String update(User user) {
		//SQL对象
		SQL sql = new SQL();
		sql.UPDATE("user");//相当于update user 
		//不需要加逗号
		if(user.getName() != null) {
			sql.SET("name = #{name}");//set会自动拼接后面的条件并且加上逗号
		}
		if(user.getPassword() != null) {
			sql.SET("password = #{password}");
		}
		if(user.getAge() != null) {
			sql.SET("age = #{age}");
		}
		sql.WHERE("id = #{id}");
		System.out.println(sql.toString());
		return sql.toString();
	}
	//多条件模糊查询
	public String selectListByCondition(User user) {
		SQL sql = new SQL();
		sql.SELECT("*");//相当于	select *
		sql.FROM("user");//相当于 from user 
		if(user.getName() != null) {
			sql.WHERE("name like concat('%',#{name},'%')");//相当于where ... 默认两个字段之间使用and
		}
		if(user.getPassword() != null) {
			sql.WHERE("password = #{password}");
		}
		if(user.getAge() != null) {
			sql.OR();//默认是and连接
			sql.WHERE("age = #{age}");
		}
		System.out.println(sql.toString());
		return sql.toString();
	}
	//批量删除
	public String deleteByIds(@Param("ids") Integer[] ids) {
		SQL sql = new SQL();
		sql.DELETE_FROM("user");//相当于 delete from user
		StringBuilder sb = new StringBuilder();
		//只能使用普通的循环
		for (int i = 0; i < ids.length; i++) {
			sb.append("#{ids["+i+"]},");
		}
		sb.deleteCharAt(sb.length()-1);//删除最后一个多余的逗号,是sb的长度-1
		sql.WHERE("id in ("+sb.toString()+")");//没有的条件可以自己拼接
		System.out.println(sql.toString());
		return sql.toString();
	}
	//批量插入
	public String insertByBatch(@Param("users") List users) {
		//当sql对象的方法满足不了我们需求时,我们需要手动拼接
		StringBuilder sb = new StringBuilder();
		sb.append("insert into user(name,password,age) values ");
		for (int i = 0; i < users.size(); i++) {
			sb.append("(#{users["+i+"].name},#{users["+i+"].password},#{users["+i+"].age}),");
		}
		sb.deleteCharAt(sb.length()-1);//将最后一个逗号去掉
		System.out.println(sb.toString());
		return sb.toString();
	}
}

多对一

实体类

department

package cn.zj.mybatis.pojo;

import java.util.List;

public class Department {
	private Integer id;
	private String name;
	
	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 Department(Integer id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	public Department() {
		super();
		// TODO Auto-generated constructor stub
	}
	
}

employee

package cn.zj.mybatis.pojo;

public class Employee {
	private Integer id;
	private String name;
	//多对一
	private Department dept;
	
	public Department getDept() {
		return dept;
	}
	public void setDept(Department dept) {
		this.dept = dept;
	}
	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;
	}
	
	@Override
	public String toString() {
		return "Employee [id=" + id + ", name=" + name + ", dept=" + dept + "]";
	}
	public Employee() {
		super();
		// TODO Auto-generated constructor stub
	}
	
}

N+1策略

public interface Many2OneMapper {
	Employee selectByPrimayKey(Integer id);
}
<?xml version="1.0" encoding="UTF-8" ?>



	
	
	
	
		
		
		
		
		
		
		
	
	

等值策略

public interface Many2OneMapper {
	Employee selectByPrimayKey(Integer id);
}

<?xml version="1.0" encoding="UTF-8" ?>


  
  
  
    
    
        
        
        
        
        
        
            
            
            
            
        
    
  

一对多

实体类

department

package cn.zj.mybatis.pojo;

import java.util.List;

public class Department {
	private Integer id;
	private String name;
	
	private List emps;
	
	public List getEmps() {
		return emps;
	}
	public void setEmps(List emps) {
		this.emps = emps;
	}
	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 Department() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Department(Integer id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	@Override
	public String toString() {
		return "Department [id=" + id + ", name=" + name + ", emps=" + emps + "]";
	}	
}

employee

package cn.zj.mybatis.pojo;

public class Employee {
	private Integer id;
	private String name;
	
	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;
	}
	@Override
	public String toString() {
		return "Employee [id=" + id + ", name=" + name + "]";
	}
	public Employee(Integer id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	public Employee() {
		super();
		// TODO Auto-generated constructor stub
	}
}

N+1策略

public interface One2ManyMapper {
	
	List selectByPrimayKey(Integer id);
}
<?xml version="1.0" encoding="UTF-8" ?>



	
	
	
	   
	   
	   
	   
	   
	   
	   
	
	
	

等值策略

public interface One2ManyMapper {
	
	List selectByPrimayKey(Integer id);
}
<?xml version="1.0" encoding="UTF-8" ?>



    
	
	
	   
	   
	   
	   
	   
	   
	   
	       
	       
	       
	       
	   
	

缓存

为什么需要缓存呢?

只有在持久层才有缓存说法。

当我们重复的去请求sql都会做IO操作。如果我们每次都从数据库中去取数据的话。会打打的影响我们的效率。

如果我们将重复的请求放在缓存那里,让第一次请求在数据库中去取,第二次,第三次都让其取缓存中取,这样就大大的提高了我们查询的效率。

缓存分为一级缓存和二级缓存。

一级缓存

一级缓存是mybatis自带的,内置在sqlSession对象中,默认是开启的。可以手动的设置关闭缓存。

session1.clearCache();关闭缓存

二级缓存

一级缓存是SqlSession对象级别,在每一次会话中有效

二级缓存是 SqlSessionFactory级别,在整个应用都有效,可以在多个会话有效

MyBatis本身并没有实现二级缓存

二级缓存需要第三方缓存提供商的支持

Ehcache -第三方缓存(Hibernate框架默认就是支持)

学习:http://www.mybatis.org/ehcache-cache/

下载Ehcache : https://github.com/mybatis/ehcache-cache/releases

mybatis默认开启二级缓存;模拟一千次sqlSession对象的请求

导入ehcache包

导入依赖的日志包

xml中映射配置二级缓存


	
       
       
       
       
       
       
       
       
       
       
	

ehcache.xml配置(配置全局的二级缓存)


	
	
	
    

因为二级缓存可以缓存到文件(将对象序列化到本地),涉及到对象序列化,那么对应的javaBean对象就必须实现 。

命中率= 从缓存中获取数据的次数/ 查询的总次数

如 : 两次查询 从缓中获取一次

0.5 = 1/2;

0.666666 = 2/3;

命中率越高缓存效果越好

DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.0
DEBUG [main] - ==>  Preparing: select * from user where id = ? 
DEBUG [main] - ==> Parameters: 3(Integer)
DEBUG [main] - <==      Total: 1
DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.5
DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.6666666666666666
DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.75
DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.8
DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.8333333333333334
DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.8571428571428571
DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.875
DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.8888888888888888
DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.9

逆向工程

就是可以根据数据库的字段动态的生成我们的实体类pojo,还有一些常用的sql语句。

首先需要安装mybatis插件在eclipse中。

然后new一个mybatis的generator,生成generatorConfig.xml配置文件。

generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>



    
        
        
            
        

        
        
        

         
        
            
        

        
        
            
            
            
            
        

        
        
            
        

        
        
            
        

        
        
       
        

逆向工程的使用

逆向工程没有生成插入方法的插入之后返回id值需手动添加。

@Test
	public void testSelectByExample() {
		// 1.创建sqlSession对象
		SqlSession session = MybatisUtils.openSqlSession();
		// 2.调用getMapper()得到代理对象
		DepartmentMapper mapper = session.getMapper(DepartmentMapper.class);
		DepartmentExample example = new DepartmentExample();
		Criteria criteria = example.createCriteria();//创建限制对象;
		//一个限制对象默认是用and连接两个字段,想要用or连接必须要创建两个限制对象。
		criteria.andIdGreaterThan(2);
		criteria.andNameLike("%部%");
		List list = mapper.selectByExample(example);
		for (Department department : list) {
			System.out.println(department);
		}
		// 5.关闭连接
		session.close();
	}
		@Test
	public void testInsert() {
		// 1.创建sqlSession对象
		SqlSession session = MybatisUtils.openSqlSession();
		// 2.调用getMapper()得到代理对象
		DepartmentMapper mapper = session.getMapper(DepartmentMapper.class);
		Department dept = new Department(null, "网络部");
		int row = mapper.insert(dept);
		System.out.println(row);
		System.out.println(dept.getId());
		// 4.提交事务
		session.commit();
		// 5.关闭连接
		session.close();
	}