MyBatis学习记录
一、MyBatis概述
1、软件开发架构——三层架构
1)界面层(User Interface layer)
- 表示层、视图层
- 和用户打交道
- 接收用户数据,显示请求的处理结果
- jsp ,html ,servlet
- 对应的包:controller包 (servlet)
- 对应的框架:servlet—springmvc(框架)
2)业务逻辑层(Business Logic Layer)
- 接收了界面层传递的数据
- 计算逻辑
- 调用数据库,获取数据
- 对应的包:service 包(XXXService类)
- 对应的框架:service类–spring(框架)
3)数据访问层(Data access layer)
- 访问数据库, 执行对数据的查询,修改,删除
- 对应的包:dao包(XXXDao类)
- 对应的框架:dao类–mybatis(框架)
4)三层中类的交互关系
用户使用界面层–> 业务逻辑层—>数据访问层(持久层)–>数据库(mysql)
2、框架
1)什么是框架
- 框架(Framework)是整个或部分系统的可重用设计
- 框架是可被应用开发者定制的应用骨架、模板
- 框架其实是半成品软件,就是一组组件
- 框架安全的,可复用的,不断升级的软件
2)为什么用框架
- 框架要解决的最重要的一个问题是技术整合
- 可以提供开发的效率
3)什么是MyBatis框架
- Mybatis是 MyBatis SQL Mapper Framework for Java (sql映射框架)
- sql mapper :sql映射
可以把数据库表中的一行数据 映射为 一个java对象。
一行数据可以看做是一个java对象。操作这个对象,就相当于操作表中的数据 - Data Access Objects(DAOs) : 数据访问 , 对数据库执行增删改查。
4)为什么使用MyBatis框架
- 使用 JDBC 的缺陷:
——代码比较多,开发效率低
——需要关注 Connection ,Statement, ResultSet 对象创建和销毁
——对 ResultSet 查询的结果,需要自己封装为 List
——重复的代码比较多些
——业务代码和数据库的操作混在一起 - MyBatis作用:
——减轻使用 JDBC 的复杂性,不用编写重复的创建 Connetion , Statement
——不用编写关闭资源代码
——直接使用 java 对象,表示结果数据
5)Mybatis提供的功能
- 提供了创建Connection ,Statement, ResultSet的能力 ,不用开发人员创建这些对象了
- 提供了执行sql语句的能力, 不用你执行sql
- 提供了循环sql, 把sql的结果转为java对象, List集合的能力
// MyBatis能内部完成以下功能,不用手动写以下代码
while (rs.next()) {
Student stu = new Student();
stu.setId(rs.getInt("id"));
stu.setName(rs.getString("name"));
stu.setAge(rs.getInt("age"));
//从数据库取出数据转为 Student 对象,封装到 List 集合
stuList.add(stu);
}
- 提供了关闭资源的能力,不用你关闭Connection, Statement, ResultSet
二、MyBatis入门
1、下载MyBatis及环境配置
1)下载地址
https://github.com/mybatis/mybatis-3/releases
2)环境路径设置
2、新建数据库表
CREATE TABLE `student` (
`id` int(11) NOT NULL ,
`name` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3、创建IDEA工程
1)创建新的Empty Project
2)创建Maven Module
,选择maven-archetype-quickstart
3)删除默认创建的App
和AppTest
4)配置Maven的pom.xml
文件
- 加入mybatis坐标
<!-- mybatis依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
- 加入mysql驱动坐标
<!-- mysql驱动依赖 -->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
- 加入插件,使resources的文件复制到target内(target中仍无,则ReBuild工程或手动复制)
<!--放入build中-->
<resources>
<resource>
<directory>src/main/java</directory><!--所在的目录-->
<includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
注:会自动下载依赖的类库至maven指定的目标文件夹中
5)创建Student实体类
- 声明与数据表相同属性及名称的变量
- 创建构造函数以及get、set方法
- 重写toString()方法
package com.bjpowernode.entity;
// 推荐实体类名称和表类一致,容易记忆
public class Student {
// 定义属性,目前要求属性名和列名一致
private Integer id;
private String name;
private String email;
private Integer age;
public Student(Integer id, String name, String email, Integer age) {
this.id = id;
this.name = name;
this.email = email;
this.age = age;
}
public Student() {
}
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 String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", age=" + age +
'}';
}
}
6)实现操作数据库的DAO接口
- 声明一个查询表内所有数据的方法,将结果放入一个列表
package com.bjpowernode.dao;
import com.bjpowernode.entity.Student;
import java.util.List;
// 接口,需要操作student表
public interface StudentDao {
// 查询student表中的所有数据
public List<Student> selectStudents();
}
7)创建一个MyBatis使用的sql映射配置文件
- 与DAO接口在同一目录文件夹下
- 配置文件名称与DAO接口保持一致,即
StudentDao.xml
- 根据MyBatis格式要求书写sql语句
<?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.bjpowernode.dao.StudentDao">
<!--
select:表示查询
id:执行sql语句的唯一标识,可以自定义,建议使用接口中的方法名称
resultType:表示结果类型,建议直接使用类型的全限定名称
不是resultSetType,写错了会报错:
必须具有列表 "FORWARD_ONLY SCROLL_INSENSITIVE SCROLL_SENSITIVE DEFAULT " 中的值
-->
<select id="selectStudents" resultType="com.bjpowernode.entity.Student">
select id,name,email,age from student order by id
</select>
</mapper>
<!--
sql映射文件:写sql语句的,MyBatis会执行这些sql
1、指定约束文件
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
其中,mybatis-3-mapper.dtd 文件是约束文件
2、约束文件作用:限制与检查当前文件中出现的标签、属性必须符合mybatis要求
3、mapper 是当前文件的根标签——默认的
namespace:为命名空间,是唯一值,也可以自定义的字符串
但要求使用DAO接口的全限定名称
4、在当前文件中,可以使用特定的标签,表示数据库的特定操作,有:
<select>
<update>
<insert>
<delete>
-->
8)创建主配置文件
- 在
src/resources/
下创建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>
<!--
环境配置:数据库的连接信息
default:必须和某个environment的id值一样
告诉mybatis使用哪个数据库的连接信息,即访问哪个数据库
-->
<environments default="My_development">
<!-- environment:一个数据库信息的配置环境
id:一个唯一值,自定义的,表示环境的名称
-->
<environment id="My_development">
<!--
transactionManager:mybatis的事务类型
type:JDBC——表示使用jdbc中的Connection对象的commit、rollback
-->
<transactionManager type="JDBC"/>
<!--
dataSource:表示数据源,链接数据库
type:表示数据源的类型,POOLED表示使用连接池
-->
<dataSource type="POOLED">
<!--
driver/user/username/password的名称是固定的,不能自定义
value里的值换成自己的
url中,数据库后面要加:?serverTimezone=UTC;否则会报错
-->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- sql mapper(sql映射文件)的位置 -->
<mappers>
<!--
一个mapper标签指定一个文件的位置
从类路径开始的路径信息
target/classes(类路径)
[先编译后,找到target中的目标sql映射文件,复制路径过来]
-->
<mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
</mappers>
</configuration>
<!--
mybatis的主配置文件:主要定义了数据库的配置信息,sql映射文件的位置
-->
9)创建测试程序文件
- 创建
MyApp.java
文件 - 读取主配置文件
mybatis.xml
以及创建Sql执行所需相关对象 - 使用sqlsession相关对象执行语句并输出
package com.bjpowernode;
import com.bjpowernode.entity.Student;
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 java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MyApp {
public static void main(String[] args) throws IOException {
// 访问mybatis读取student表的数据
// 1.定义mybatis主配置文件的名称,从类路径的根目录开始(target/classes)
String config = "mybatis.xml"; // 即之前定义的resources下的主配置文件
// 2.读取config文件
InputStream in = Resources.getResourceAsStream(config);
// 3.创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 4.利用builder创建SqlSessionFactory对象
SqlSessionFactory factory = builder.build(in);
// 5.从factory中获取SqlSession对象 【重点】
SqlSession sqlsession = factory.openSession();
// 6.指定要执行的sql语句的标识,即通过sql映射文件中的namespace + '.' + 标签的id值 【重点】
String sqlId = "com.bjpowernode.dao.StudentDao" + '.' + "selectStudents";
// 7.通过sqlId执行sql语句
List<Student> stuList = sqlsession.selectList(sqlId);
// 8.输出结果
for(Student stu : stuList){
System.out.println("查询的学生信息:" + stu);
}
// 9.关闭sqlsession对象
sqlsession.close();
}
}
结果如下:
10)总体流程和文件
- 首先,pom.xml 文件——添加配置mybatis、mysql以及资源自动复制插件
- 其次,编写实体类程序——定义相关变量,与数据表结构内容相一致
- 接着,实体类的DAO文件——声明相应方法
- 然后,创建DAO文件相对应的sql映射mapper(xml)文件,用于编写sql语句
- 再其次,编写主配置xml文件,将上一步的sql映射文件配置好,确定访问的数据库以及数据库连接信息
- 最后,创建实际的应用、测试程序文件,进行功能的实现
11)配置日志功能 - mybatis.xml 文件加入日志配置,可以在控制台输出执行的 sql 语句和参数
<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
4、增删改的语句
1)增加信息
<insert id="insertStudent">
insert into student(id,name,email,age) values(#{id},#{name},#{email},#{age})
</insert>
2)删除信息
<delete id="deleteStudent">
delete from student where id=#{studentId}
</delete>
3)修改信息
<update id="updateStudent">
update student set age = #{age} where id=#{id}
</update>
5、MyBatis使用的sql相关对象
1)Resources 类
InputStream in = Resources.getResourceAsStream("mybatis.xml");
- mybatis中的一个类, 负责读取主配置文件
2)SqlSessionFactoryBuilder
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
- 创建SqlSessionFactoryBuilder对象
3)SqlSessionFactory
SqlSessionFactory factory = builder.build(in);
- 创建SqlSessionFactory对象,程序创建耗时比较长,使用资源比较多,在整个项目中,有一个就够用了
- 作用是获取SqlSession对象:
SqlSession sqlSession = factory.openSession();
- openSession(true) 获取自动提交事务的SqlSession.
openSession(false) 非自动提交事务的SqlSession对象
参数为空时,默认为false
4)SqlSession
- 定义了操作数据的方法:selectOne() ,selectList() ,insert(),update(), delete(), commit(), rollback()
- SqlSession对象不是线程安全的:需要在方法内部使用, 在执行sql语句之前,使用openSession()获取SqlSession对象;在执行完sql语句后,需要关闭它,执行SqlSession.close()
6、MyBatis工具类创建与使用
1)创建MyBatisUtils工具类
src/../utils/
下创建MyBatisUtils.java
- 实现能返回sqlSession对象
package com.bjpowernode.entity;
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 java.io.IOException;
import java.io.InputStream;
public class MyBatisUtils {
// 通过静态代码块创建factory对象
private static SqlSessionFactory factory = null;
static {
String config = "mybatis.xml";
try {
InputStream in = Resources.getResourceAsStream(config);
factory = new SqlSessionFactoryBuilder().build(in);
} catch (IOException e) {
e.printStackTrace();
}
}
// 通过静态方法返回sqlSession对象
public static SqlSession getSqlSession(){
SqlSession sqlSession = null;
if(factory != null){
sqlSession = factory.openSession();
}
return sqlSession;
}
}
2)工具类的使用
package com.bjpowernode;
import com.bjpowernode.entity.MyBatisUtils;
import com.bjpowernode.entity.Student;
import org.apache.ibatis.session.SqlSession;
import java.io.IOException;
import java.util.List;
public class MyApp2 {
public static void main(String[] args) throws IOException {
// 获取sqlsession对象
SqlSession sqlsession = MyBatisUtils.getSqlSession();
// 指定要执行的sql语句的标识,即通过sql映射文件中的namespace + '.' + 标签的id值 【重点】
String sqlId = "com.bjpowernode.dao.StudentDao" + '.' + "selectStudents";
// 通过sqlId执行sql语句
List<Student> stuList = sqlsession.selectList(sqlId);
// 输出结果
for(Student stu : stuList){
System.out.println("查询的学生信息:" + stu);
}
// 关闭sqlsession对象
sqlsession.close();
}
}
三、MyBatis动态代理
1、实现步骤
1)不再使用Dao的接口实现类
2)getMapper获取代理对象
- 动态代理: 使用SqlSession.getMapper(dao接口.class) 获取这个dao接口的对象
- 获取方法1:
SqlSession session = factory.openSession();
StudentDao studentDao = session.getMapper(StudentDao.class);
- 获取方法2:
StudentDao studentDao = MyBatisUtil.getSqlSession().getMapper(StudentDao.class);
3)使用Dao代理对象方法来执行sql语句
// select 方法:
@Test
public void testSelect() throws IOException {
List<Student> studentList = studentDao.selectStudents();
studentList.forEach( stu -> System.out.println(stu));
}
// insert 方法:
@Test
public void testInsert() throws IOException {
Student student = new Student();
student.setId(1006);
student.setName("林浩");
student.setEmail("linhao@163.com");
student.setAge(26);
int nums = studentDao.insertStudent(student);
System.out.println("使用 Dao 添加数据:"+nums);
}
// update 方法
@Test
public void testUpdate() throws IOException {
Student student = new Student();
student.setId(1006);
student.setAge(28);
int nums = studentDao.updateStudent(student);
System.out.println("使用 Dao 修改数据:"+nums);
}
// delete 方法
@Test
public void testDelete() throws IOException {
int nums = studentDao.deleteStudent(1006);
System.out.println("使用 Dao 修改数据:"+nums);
}
2、传入参数
1)parameterType
- 写在mapper文件中的 一个属性
- 表示dao接口中方法的参数的数据类型
- 它的值是java的数据类型全限定名称或者是mybatis定义的别名
- 不是强制的,mybatis通过反射机制能够发现参数类型,所以可以没有,默认不写
别名 | 映射的类型 |
---|---|
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
2)传入一个简单参数
- Dao接口方法的参数只有一个简单类型(java 基本类型和 String),即只有一个占位符 #{任意字符}
- 使用#{}之后,mybatis执行sql,其实是使用jdbc中PreparedStatement对象,其实际过程:
mybatis创建Connection、PreparedStatement对象String sql = "..... =?;"
PreparedStatement ps = conn.preparedStatement(sql);
ps.setInt(1, num);
执行sql封装,将其封装为resultType对象ResultSet rs = ps.executeQuery():
while(rs.next()){...}
3)传入多个参数 1——使用@Param
- 多个参数情况下,使用@Param自己命名参数
- 如存在接口
public List<Student> selectMulitParam(@Param("myname") String name, @Param("myage") Integer age)
其中,@Param("参数名") String name
使用时如下:
<!-- mapper文件中,也方便了编写 -->
<select>
select * from s_table where name=#{myname} or age=#{myage}
</select>
4)传入多个参数 2——使用对象
- 多个参数,使用java对象,java 的属性值就是 sql 需要的参数值
- 语法格式:
#{ property, javaType=java 中数据类型名,jdbcType=数据类型名称 }
- javaType, jdbcType 的类型 MyBatis 可以检测出来,一般不需要设置。常用格式 #{ property }
- 实现步骤:
创建保存参数值的对象 QueryParam.java
接口中声明方法
mapper文件修改配置
测试类调用方法传参
package com.bjpowernode.vo;
public class QueryParam {
private String queryName;
private int queryAge;
//set ,get 方法
}
List<Student> selectMultiObject(QueryParam queryParam);
<select id="selectMultiObject" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name=#{queryName} or age =#{queryAge}
</select>
@Test
public void selectMultiObject(){
QueryParam qp = new QueryParam();
qp.setQueryName("李力");
qp.setQueryAge(20);
List<Student> stuList = studentDao.selectMultiObject(qp);
stuList.forEach( stu -> System.out.println(stu));
}
5)传入多个参数 3——按位置传参
- 参数位置从 0 开始, 引用参数语法 #{ arg 位置 } , 第一个参数是#{arg0}, 第二个是#{arg1}
List<Student> selectByNameAndAge(String name,int age);
<select id="selectByNameAndAge" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name=#{arg0} or age =#{arg1}
</select>
@Test
public void testSelectByNameAndAge(){
//按位置参数
List<Student> stuList = studentDao.selectByNameAndAge("李力",20);
stuList.forEach( stu -> System.out.println(stu));
}
6)传入多个参数 4——使用Map
- Map 集合可以存储多个值,使用Map向 mapper 文件一次传入多个参数
- Map 集合使用 String的 key,Object 类型的值存储参数
- mapper 文件使用 # { key } 引用参数值
Map<String,Object> data = new HashMap<String,Object>();
data.put(“myname”,”李力”);
data.put(“myage”,20);
List<Student> selectMultiMap(Map<String,Object> map);
<select id="selectMultiMap" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name=#{myname} or age =#{myage}
</select>
@Test
public void testSelectMultiMap(){
Map<String,Object> data = new HashMap<>();
data.put("myname","李力");// #{myname}
data.put("myage",20); // #{myage}
List<Student> stuList = studentDao.selectMultiMap(data);
stuList.forEach( stu -> System.out.println(stu));
}
6)占位符 # 与 $
- #:占位符,告诉 mybatis 使用实际的参数值代替
- 并使用 PrepareStatement 对象执行 sql 语句, #{…}代替sql 语句的“?”,避免了SQL注入
- $ 字符串替换,告诉 mybatis 使用$包含的“字符串”替换所在位置
- 使用 Statement 把 sql 语句和${}的内容连接起来。主要用在替换表名,列名,不同列排序等操作。
- 能确定数据是安全时,可以使用$
select id,name, email,age from student where id=#{studentId}
# 的结果: select id,name, email,age from student where id=?
select id,name, email,age from student where id=${studentId}
$ 的结果:select id,name, email,age from student where id=1001
# 和 $区别
1. #使用 ?在sql语句中做站位的, 使用PreparedStatement执行sql,效率高
2. #能够避免sql注入,更安全。
3. $不使用占位符,是字符串连接方式,使用Statement对象执行sql,效率低
4. $有sql注入的风险,缺乏安全性。
5. $:可以替换表名或者列名
3、MyBatis输出结果——Java对象
1)resultType
- 执行 sql 得到 ResultSet 转换的类型,使用类型的完全限定名或别名
- 如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身
- resultType可以有:简单类型、对象类型以及集合类型
<select id="countStudent" resultType="int">
select count(*) from student
</select>
<select id="selectById" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where id=#{studentId}
</select>
<select id="selectReturnMap" resultType="java.util.HashMap">
select name,email from student where id = #{studentId}
</select>
2)resultMap
- 可以自定义 sql 的结果和 java 对象属性的映射关系
- 常用在列名和 java 对象属性名不一样的情况
- 使用方式:
1.先定义 resultMap,指定列名和属性的对应关系。
2.在中把 resultType 替换为 resultMap。
<!-- 创建 resultMap
id:自定义的唯一名称,在<select>使用
type:期望转为的 java 对象的全限定名称或别名
-->
<resultMap id="studentMap" type="com.bjpowernode.domain.Student">
<!-- 主键字段使用 id -->
<id column="id" property="id" />
<!--非主键字段使用 result-->
<result column="name" property="name"/>
<result column="email" property="email" />
<result column="age" property="age" />
</resultMap>
<!--resultMap: resultMap 标签中的 id 属性值-->
<select id="selectUseResultMap" resultMap="studentMap">
select id,name,email,age from student where name=#{queryName} or age=#{queryAge}
</select>
3)类属性名与数据表列名不同
- 方法1——sql语句使用"as"关键词,即列别名
- 方法2——使用resultMap方法
4)模糊like查询的两种方案
- 方法1——提前准备好like的内容
List<Student> selectLikeFirst(String name);
<select id="selectLikeFirst" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student
where name like #{studentName}
</select>
@Test
public void testSelectLikeOne(){
String name="%力%";
List<Student> stuList = studentDao.selectLikeFirst(name);
stuList.forEach( stu -> System.out.println(stu));
}
- 方法2——mapper 文件中使用 like name “%” #{xxx} “%” 拼接查询
List<Student> selectLikeSecond(String name);
<select id="selectLikeSecond" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student
where name like "%" #{studentName} "%"
</select>
@Test
public void testSelectLikeSecond(){
String name="力";
List<Student> stuList = studentDao.selectLikeSecond(name);
stuList.forEach( stu -> System.out.println(stu));
}
四、动态sql
1、什么是动态sql
- 动态 SQL,通过 MyBatis 提供的各种标签对条件作出判断以实现动态拼接 SQL 语句
- 条件判断使用的表达式为 OGNL 表达式
- 常用的动态 SQL 标签有< if >、< where >、< choose/ >、< foreach >
- 主要用于解决查询条件不确定的情况
2、动态sql标签
1)< if > 是判断条件
- 当 test 的值为 true 时,会将其包含的 SQL 片断拼接到其所在的 SQL 语句中
- 语法:< if test=”条件” > sql 语句的部分 < /if >
List<Student> selectStudentIf(Student student);
<select id="selectStudentIf" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student
where 1=1
<if test="name != null and name !='' ">
and name = #{name}
</if>
<if test="age > 0 ">
and age > #{age}
</if>
</select>
2)< where > 用来包含多个< if >标签
- 若 where 后的所有< if/ >条件均为 false,而 where 后若又没有 1=1 子句,则 SQL 中就会只剩下一个空的 where,SQL出错
- 在 where 后,需要添加永为真子句 1=1,以防止这种情况的发生,但当数据量很大时,会严重影响查询效率
- 而使用 < where >标签,当多个if有一个成立的,会自动增加一个where关键字,并去掉 if中多余的 and ,or等
- 语法:< where > 其他动态 sql < /where >
List<Student> selectStudentWhere(Student student);
<select id="selectStudentWhere" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student
<where>
<if test="name != null and name !='' ">
and name = #{name}
</if>
<if test="age > 0 ">
and age > #{age}
</if>
</where>
</select>
3)< foreach > 循环java中的数组集合
- 主要用在sql的in语句中
- collection 表示要遍历的集合类型, list ,array 等
- open, close, separator 为对遍历内容的 SQL 拼接
- 语法:
<foreach collection="集合类型" open="开始的字符" close="结束的字符" item="集合中的成员" separator="集合成员之间的分隔符">
#{item 的值}
</foreach>
4)代码片段——复用一些语法
- < sql/ >标签用于定义 SQL 片段,以便其它 SQL 标签复用
- 而其它标签使用该 SQL 片断,需要使用< include/ >子标签
- 使用步骤:
1.先定义 < sql id=“自定义名称唯一” > sql语句, 表名,字段等 < /sql >
2.再使用, < include refid=“id的值” / >
<!--创建 sql 片段 id:片段的自定义名称-->
<sql id="studentSql">
select id,name,email,age from student
</sql>
<select id="selectStudentSqlFragment" resultType="com.bjpowernode.domain.Student">
<!-- 引用 sql 片段 -->
<include refid="studentSql"/>
<if test="list !=null and list.size > 0 ">
where id in
<foreach collection="list" open="(" close=")" item="stuobject" separator=",">
#{stuobject.id}
</foreach>
</if>
</select>
五、MybBatis配置文件
settings是 MyBatis 中全局的调整设置,它们会改变 MyBatis 的运行时行为,应谨慎设置
- 缓存
<!-- 该配置影响的所有映射器中配置的缓存的全局开关。默认值true -->
<setting name="cacheEnabled" value="true"/>
- 延迟加载(懒加载)
<!--延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。默认值false -->
<setting name="lazyLoadingEnabled" value="true"/>
- 返回多行数据
<!-- 是否允许单一语句返回多结果集(需要兼容驱动)。 默认值true -->
<setting name="multipleResultSetsEnabled" value="true"/>
- 列标签代替列名
<!-- 使用列标签代替列名。不同的驱动在这方面会有不同的表现, 具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果。默认值true -->
<setting name="useColumnLabel" value="true"/>
- JDBC自动生成主键
<!-- 允许 JDBC 支持自动生成主键,需要驱动兼容。 如果设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工作(比如 Derby)。 默认值false -->
<setting name="useGeneratedKeys" value="false"/>
- 指定对象方法触发延迟加载
<!-- 指定哪个对象的方法触发一次延迟加载。 -->
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
1、数据库属性配置文件
1)目的与作用
- 把数据库连接信息放到一个单独的文件中
- 将其和mybatis主配置文件分开
- 便于修改,保存,处理多个数据库的信息
2)实现步骤
- 在resources目录中定义一个属性配置文件,xxxx.properties ,例如 jdbc.properties
- 在属性配置文件中定义数据,格式是 key=value
- 其中,key一般使用’.'来做多级目录的分割,例如 jdbc.mysql.driver
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql//.....
jdbc.username=root
jdbc.password=123456
- 在mybatis的主配置文件,使用< property > 指定文件的位置
<properties resource="jdbc.properties" />
- 在需要使用值的地方${key}
<dataSource type="POOLED">
<!--使用 properties 文件: 语法 ${key}-->
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
2、mappers映射器
1)对于单独映射文件
- 常使用
<mapper resource=" " />
- 使用相对于类路径的资源,从 classpath 路径查找文件
- 例如:
<mapper resource="com/bjpowernode/dao/StudentDao.xml" />
- 缺点:当映射文件过多,添加过于冗杂
2)对于指定包下所有接口及其映射文件
- 使用
<package name=""/>
- 要求 Dao 接口名称和 mapper 映射文件名称相同,且在同一个目录中
- 例如:
<package name="com.bjpowernode.dao"/>
六、MyBatis扩展之——PageHelper
PageHelper用于实现数据分页,PageHelper 支持多种数据库
1、基于 PageHelper 分页
1)实现步骤
- maven坐标
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.10</version>
</dependency>
- 加入plugin配置
<!--在<environments>之前加入-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor" />
</plugins>
- 创建PageHelper 对象:要进行分页的 MyBatis 查询方法前调用 PageHelper.startPage 静态方法即可
@Test
public void testSelect() throws IOException {
//获取第 1 页,3 条内容
PageHelper.startPage(1,3);
List<Student> studentList = studentDao.selectStudents();
studentList.forEach( stu -> System.out.println(stu));
}