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
Test.java:
public void testSelect() throws IOException{
SqlSession openSession = initSqlSessionFactory().openSession();
UserDao userDao = openSession.getMapper(UserDao.class);
try {
List
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
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
return keys;
}
public void setKeys(List
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文件:
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
+ "]";
}
}
package com.luyi.bean;
import java.util.List;
public class Lock {
private Integer id;
private String lockName;
private List
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
return keys;
}
public void setKeys(List
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
}
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
}
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
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 元素来引用另外一个缓存。
作者:卢一
出处:http://www.cnblogs.com/luyi001/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

浙公网安备 33010602011771号