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):




















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








测试(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-引入外部配置文件

代码示例:




















settings-修改mybatis的运行时行为

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





typeAliases-给java类型起别名

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






typeHandlers-类型处理器

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



plugins插件

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

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

environments-配置环境

代码示例:













databaseIdProvider-用于数据库移植

代码示例:

全局配置文件:





SQL映射文件:

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里的属性

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



insert into user(username, password, role) values(#{username}, #{password}, #{role})

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




select max(id) + 1 from user

insert into user(username, password, role) values(#{username}, #{password}, #{role})

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映射文件:

...

...

UserDao.java:

public List getAll();

Test.java:

public void testSelect() throws IOException{
SqlSession openSession = initSqlSessionFactory().openSession();
UserDao userDao = openSession.getMapper(UserDao.class);

try {
List 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:

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:

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映射文件:

...







联合查询(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映射配置文件:






















properties文件(dbconfig):

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

全局配置文件:





















测试文件(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 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 getKeys() {
return keys;
}
public void setKeys(List 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:
















测试文件: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:













LockDao.xml:




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

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

按需加载的配置:






注意:设置了按需加载的配置之后,使用分步查询时,不会马上两条查询语句都发出去,而是按需加载,当我们需要使用另一个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 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 getKeys() {
return keys;
}
public void setKeys(List 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 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:

























log4j.xml:


<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

















</log4j:configuration>

KeyDao.xml:













LockDao.xml:










测试文件(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):





dbconfig.properties:

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

mybtais-config.xml:
























测试文件(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,防止报错,如:

trim标签的使用:

trim截取字符串:

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

代码示例:

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 getTeachersByids(@Param("ids")List ids);
}

TeacherDao.xml:




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 list = Arrays.asList(1, 2, 3);
List result = teacherDao.getTeachersByids(list);
System.out.println(result);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
openSession.close();
}
}
}

choose标签的使用

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

代码实现:




id=#{id} and


teacherName like teacherName and


birth < #{birth}


1=1


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

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

代码实现:

其他标签

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  阅读(262)  评论(0)    收藏  举报