yBatis另一个核心要素就是核心配置文件。一个完整的核心配置文件的标签包括:
注意:文件中的元素节点是有一定顺序的,节点位置必须按以上位置排序,否则会编译错误
SqlSessionFactoryBuilder(构造器)
SqlSessionFactory(工厂接口)
SqlSession(会话)
SQL Mapper(映射器)
properties 标签可以通过 resource属性指定外部 properties 文件 (databaseproperties),也可以通过 properties 子元素配置.
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
jdbc.username=root
jdbc.password=root
log4j.rootLogger=TRACE,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
#log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=wocao.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %F %p %m%n
log4j.logger.mapperNS =TRACE
log4j.logger.com.mybatis=DEBUG
log4j.logger.com.mybatis.common.jdbc.SimpleDataSource=DEBUG
log4j.logger.com.mybatis.common.jdbc.ScriptRunner=DEBUG
log4j.logger.com.mybatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.org.springframework=error
log4j.logger.org.apache=ERROR
log4j.logger.org.mybatis=DEBUG
也可以不使用properties标签,直接将属性值写在value中。
setings 标签用于配置 MyBatis 的运行时行为,它能深刻的影响 MyBatis 的底层运行,一般不需要大量配置,大部分情况下使用其默认值即可。所以在大部分情况下不需要大量配置它,只需要修改一 些常用的规则即可,比如自动映射、驼峰命名映射、级联规则、是否启动缓存、执行器(Executor)类型等。setting配置项说明,可参考官网settings 设置。
settings 的配置项很多,但是真正用到的不会太多,常用的配置项比如关于缓存的cacheEnabled,关于级联的 azyLoadingEnabied和aggressiveLazyLoading,关于自动映射的 autoMappingBehavior和 mapUnderscoreToCamelCase,关于执行器类型的defaultExecutorType 等。
package com.zhao.bean;
public class User {
private Integer uid;
private String username;
private String password;
private String phone;
private String address;
public User() {
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
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 getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"uid=" + uid +
", username='" + username + '\'' +
", password='" + password + '\'' +
", phone='" + phone + '\'' +
", address='" + address + '\'' +
'}';
}
}
package com.zhao.dao;
import com.zhao.bean.User;
import java.util.List;
public interface UserDao {
//模糊查询
List seach(User user);
}
mybatis通过where标签来设定查询的条件,在查条件中可以使用标签来进行条件的判断:
注意:where标签会自动忽略第一个and关键词;
package com.zhao.test;
import com.mysql.cj.Session;
import com.zhao.bean.User;
import com.zhao.dao.UserDao;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class UserTest {
//1.加载核心配置的文件字节输入流
InputStream stream=null;
//2.创建SalSessionFactory的构建对象--框架使用的是构建者模式
SqlSessionFactoryBuilder builder=null;
//3.通过构建对象加载配置文件的输入流获取SqlSessionFactory
SqlSessionFactory factory=null;
//4.通过工厂对象获取SqlSession对象--执行jabc的
SqlSession sqlSession=null;
//5.通过SqlSession对象获取接口对应的代理对象
UserDao userDao=null;
@Before
public void init() throws IOException {
stream= Resources.getResourceAsStream("mybatis.xml");
builder=new SqlSessionFactoryBuilder();
factory = builder.build(stream);
sqlSession= factory.openSession();
userDao=sqlSession.getMapper(UserDao.class);
}
@Test
//模糊查询
public void testSeach(){
User seach=new User();
seach.setUsername("李");
seach.setAddress("许昌");
List userList = userDao.seach(seach);
for (User user:userList){
System.out.println(user);
}
}
@After
public void distory() throws IOException {
sqlSession.commit();
sqlSession.close();
stream.close();
}
}
package com.zhao.bean;
public class Student {
private Integer id;
private String name;
private Integer age;
private String gender;
private double score;
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 Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", score=" + score +
'}';
}
}
//1.插入一个学生的信息
int add(Student student);
insert into student(name,age,gender,score) values(#{name},#{age},#{gender},#{score});
@Test
//4.插入一个学生的信息
public void testAdd(){
Student student=new Student();
student.setName("李文彬");
student.setAge(19);
student.setGender("女");
student.setScore(66);
int i = studentDao.add(student);
if (i>0){
System.out.println("新增成功");
}else {
System.out.println("新增失败");
}
}
//6.删除一个学生的信息
int delete(int id);
delete from student where id=#{id};
@Test
//6.删除一个学生的信息
public void testDelete(){
int i = studentDao.delete(3);
if (i>0){
System.out.println("删除成功");
}else {
System.out.println("删除失败");
}
}
//5.更新一个学生的信息
int update(Student student);
update student set name=#{name},age=#{age},gender=#{gender},score=#{score} where id=#{id};
@Test
public void testUpdate(){
//1.数据回显
Student olduser = studentDao.selectById(3);
System.out.println("修改前:"+olduser);
//2.根据需要修改字段值
olduser.setName("lisa");
olduser.setAge(18);
olduser.setGender("女");
olduser.setScore(99);
//3.执行数据库更新
studentDao.update(olduser);
//4.再次查询
Student student=studentDao.selectById(3);
System.out.println("修改后:"+student);
}
//2.查询所有学生的信息,并按照成绩从高到低排序
List selectAll();
//2.查询所有学生的信息,并按照成绩从高到低排序.
@Test
public void testSelectAll(){
List studentList = studentDao.selectAll();
for (Student student:studentList){
System.out.println(student);
}
}
在UserMapper.xml中有很多标签,每个标签都有一些参数,下面详细介绍一下相关细节。
select标签用于执行查询操作
以上是一个id为findByld的映射语句,参数类型为integer,返回结果类型为 User。
以上是一个id为findByName的映射语句,参数类型为String,返回结果类型为User。
以上是一个id为findTotal的映射语句,返回结果类型为int。
执行 SOL语句时可以定义参数,参数可以是一个简单的参数类型,nt,flatString;也可以是一个复杂的参数类型,例如lavaBean、Map等。MvBatis提供了强大的映射规则,执行SQL后,MvBatis 会将结果集自动映射到JavaBean中。
为了使数据库的查询结果和返回值类型中的属性能够自动匹配,通常会对 MYSOL 数据库和avaBean 采用同一套命名规则,即lava命名驰峰规则,这样就不露要再做映射了(数据库表字名和属性名不一致时需要手动映射)
参数的传递使用#{参数名},相当于告诉MyBatis生成PreparedStatement参数。
select标签常用属性
属性名称 |
描述 |
备注 |
id |
它和Mapper的命名空间组合起来使用,是唯一标识符,供MyBatis调用 |
如果命名空间+id不唯一,那么 MyBatis 抛出异常 |
parameterType |
表示传入 SQL 语句传入参数类型的全限定名或别名。它是一个可选属性,MyBatis 能推断出具体传入语句的参数 |
支持基本数据类型和 JavaBean、Map 等复杂数据类型 |
resultType |
SQL 语句执行后返回的类型(全限定名或者别名)。如果是集合类型,返回的是集合元素的类型,返回时可以使用 resultType 或 resultMap 之一 |
- |
resultMap |
它是映射集的引用,与 |
是 MyBatis 最复杂的元素,可以配置映射规则、级联、typeHandler 等 |
flushCache |
用于设置在调用 SQL 语句后是否要求 MyBatis 清空之前查询的本地缓存和二级缓存 |
默认值为 false,如果设置为 true,则任何时候只要 SQL 语句被调用都将清空本地缓存和二级缓存 |
useCache |
启动二级缓存的开关,默认值为true,表示将查询结果存入二级缓存 中 |
- |
timeout |
用于设置超时参数,单位是秒(s),超时将抛出异常 |
- |
fetchSize |
获取记录的总条数设定 |
默认值是数据库厂商提供的JDBC驱动所设置的条数 |
statementType |
告诉MyBatis使用哪个JDBC的Statement工作,取值为STATEMENT (Statement)、PREPARED (PreparedStatement)CALLABLE (CallableStatement) |
- |
resultSetType |
这是针对JDBC的ResultSet接口而言,其值可设置为FORWARDONLY(只允许向前访问)、SCROLL SENSITIVE(双向滚动,但不及时更新)、SCROLLJNSENSITIVE(双向滚动,及时更新) |
- |
方式一
List userList=userMapper.findByName("%王%");
方式二
List users = userMapper.findByName("王");
${value)的写法就是固定的,不能写成其它名字
insert标签
MyBatis insert 标签用来定义插入语句,执行插入操作。当 MyBatis 执行完一条插入语句后,就会返回其影响数据库的行数。
下面通过一个示例演示 insert 标签的具体用法。
修改 WebsiteMapper.xml,增加插入语句,代码如下
insert into website(name)
values(#{name})
在 WebsiteMapper 接口中定义一个 add() 方法,代码如下。
public int addWebsite(String name);
参数为 Sting 类型的字符串;返回值为 int 类型,即执行 SQL 后,插入记录的行数。
测试代码如下。
//插入 name 为编程帮4 的记录
String name = "编程帮4";
int i = websiteMapper.addWebsite(name);
System.out.println("共插入了 " + i + " 条记录");
执行测试代码,控制台输出如下
共插入了 1 条记录
其他的属性在select标签中
属性名称 |
描述 |
备注 |
keyProperty |
该属性的作用是将插入操作的返回值赋给 PO 类的某个属性,通常为主键对应的属性。如果是联合主键,可以将多个值用逗号隔开。 |
- |
useGeneratedKe |
该属性用来设置,是否使用 JDBC 提供的 getGenereatedKeys() 方法,获取数据库内部产生的主键并赋值到 keyProperty 属性设置的请求对象的属性中,例如 MySQL、SQL Server 等自动递增的字段,其默认值为 false。 |
该属性值设置为 true 后,会将数据库生成的主键回填到请求对象中,以供其他业务使用。 |
databaseId |
取值范围 oracle、mysql 等,表示数据库厂家;元素内部可通过 |
MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。 MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的所有语句。 如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃。 |
keyColumn |
该属性用于设置第几列是主键,当主键列不是表中的第 1 列时,就需要设置该属性。如果是联合主键,可以将多个值用逗号隔开。 |
- |
注意:insert 标签中没有 resultType 属性,只有查询操作才需要对返回结果类型进行相应的指定。
前面我们的 SOL 都是比较简单,有些时候业务逻辑复杂时,我们的 SOL 是动态变化的,此时在前面的学习中我们的 SQL 就不能满足要求了。开发人员通常需要手动拼接 SQL语句。根据不同的条件拼接 SQL 语句是一件极其痛苦的工作。动态 SQ大大减少了编写代码的工作量,更体现了MyBatis的灵活性、高度可配置性和可维护性。
元素 |
作用 |
备注 |
if |
判断语句 |
单条件分支判断 |
choose (when、otherwise) |
相当于Java中的switchcase语句 |
多条件分支判断 |
trim、where |
辅助元素 |
用于处理一些SQL拼装问题 |
foreach |
循环语句 |
在in语句等列举条件常用 |
set |
辅助元素 |
更新判断 |
if类似于Java中的if语句,是MyBatis中最常用的判断语句。
if语句常常与test属性联合使用语法如下。
SQL语句
当判断条件为true时,才会执行所包含的SQL语句。
最常见的场景是在if语句中包含where子句,例如:
也可以多个if语句同时使用。例如。
示例:
在上面的案例中,SOL语句中加入了一个条件"1=1",如果没有加入这个条件,那么可能就会变成下面这样一条错误的语句。
select id,username,sex,age,address from t_user and username like comcat('%',#{username},'%')
显然以上语句会出现SQL语法异常,但加入“1=1"这样的条件又非常别扭所以MyBatis提供了where标签where标签主要用来简化SQL语句中的条件判断,可以自动处理AND/OR条件,语法如下
AND/OR...
if语句中判断条件为true 时,where 关键字才会加入到组装的 SQL里面,否则就不加入。where 会检索语句,它会将where 后的第-个SQL条件语句的AND或者OR关键词去掉。
示例:
在Mybatis 中,update 语句可以使用 set 标签动态更新列。set 标签可以为 SQL 语句动态的添加 set 关键字,剔除追加到条件末尾多余的逗号。语法如下。
update 表名
列名1=#{属性名}
列名1=#{属性名}
...
where
对于一些SQL语句中含有in 条件,需要迭代条件集合来生成的情况,可以使用foreach 来实现 SQL条件的迭代。
foreach 标签用于循环语句,它很好的支持了数据和 List、set 接口的集合,并对此提供历的功能。语法格式如下
参数值
foreach标签主要有以下属性,说明如下。
item:表示集合中每一个元素进行迭代时的别名。
index:指定一个名字,表示在迭代过程中每次迭代到的位置。
open:表示该语句以什么开始(既然是in条件语句,所以必然以(开始)
separator:表示在每次进行选代之间以什么符号作为分隔符(既然是in 条件语句,所以必然以,作为分隔符)。
close:表示该语句以什么结束(既然是in条件语句,所以必然以)开始)。
主要有以下3种情况:
如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map,实际上如果你在传入参数的时候,在里面也是会把它封装成一个Map的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key
示例:
select * from tuser WHERE username like '%张%' and id in (10,89,16)
批量删除的代码示例:
//批量删除
int delBatch(DeIVO deIVO);
delete from student where id in
#{id}
对应的测试代码:
//批量删除
@Test
public void testDelBatch() {
List ids = new ArrayList<>();
ids.add(1);
ids.add(3);
for (Integer in : ids) {
System.out.println(in);
}
DeIVO deIVO = new DeIVO();
deIVO.setIds(ids);
studentDao.delBatch(deIVO);
}
使用缓存在一定程度上可以大大提高数据的读目取性能,尤其是对于查询量大和使用频繁的数据,其缓存命中率越高,越能体现出使用缓存的作用。MyBatis 作为持久层框架,也提供了使用缓存的功能。
MyBatis中缓存分为一级缓存和二级缓存,默人情况下一级缓存是开启的,而且是不能关闭的。因此我们常说的MyBatis 缓存,都是指二级缓存。