Mybatis框架
一、Mybatis框架简介
1.1 传统JDBC的缺陷
(1)数据库连接创建、释放频繁会造成系统资源浪费
【MyBatis通过在核心配置文件中配置数据路连接池解决此问题】
(2) SQL语句在代码中硬编码(PreparedStatement向占位符传参数),造成代码不易维护。
【MyBatis将SQL写在映射文件中,并支持动态SQL,通过Statement中的parameterType定义输入参数的类型】
(3) JDBC对结果集解析存在硬编码(查询列名),SQL变化导致解析代码变化,造成系统不易维护。
【通过Statement中的resultType定义输出结果的类型】
2.2 MyBatis定义
MyBatis是一个支持普通SQL查询、存储过程以及高级映射的持久层框架,它消除了几乎所有的JDBC代码和参数的手动设置以及对结果集的检索,使用简单的XML或注解进行配置和原始映射,将接口和Java的POJO映射成数据库中的记录,使得Java开发人员可以使用面向对象的编程思想来操作数据库。
2.3 ORM对象关系映射
MyBatis框架是一个ORM(Object/Relation Mapping,即对象关系映射)框架。所谓的ORM就是一种为了解决面向对象与关系型数据库中数据类型不匹配的技术,它通过描述Java对象与数据库表之间的映射关系,自动将Java应用程序中的对象持久化到关系型数据库的表中。
二、MyBatis工作原理
(1)MyBatis读取核心配置文件mybatis-config.xml:mybatis-config.xml核心配置文件主要配置了MyBatis的运行环境等信息。
(2)加载映射文件Mapper.xml:Mapper.xml文件即SQL映射文件,该文件配置了操作数据库的SQL语句,需要在mybatis-config.xml中加载才能执行。
(3)构造会话工厂:通过MyBatis的环境等配置信息构建会话工厂SqlSessionFactory,用于创建SqlSession。
(4)创建会话对象:由会话工厂SqlSessionFactory创建SqlSession对象,该对象中包含了执行SQL语句的所有方法。
(5)创建执行器:会话对象本身不能直接操作数据库,MyBatis底层定义了一个Executor接口用于操作数据库,执行器会根据SqlSession传递的参数动态的生成需要执行的SQL语句,同时负责查询缓存地维护。
(6)封装SQL信息:SqlSession内部通过执行器Executor操作数据库,执行器将待处理的SQL信息封装到MappedStatement对象中。
(7)操作数据库:根据动态生成的SQL操作数据库。(8)输出结果映射:执行SQL语句之后,通过MappedStatement对象将输出结果映射至Java对象中。
三、MyBatis的核心对象
java
SqlSessionFactoryBuilder
SqlSessionFactory
SqlSession
3.1 SqlSessionFactoryBuilder对象
-
**作用:**用来创建SqlSessionFactory工厂对象
-
**方法:**按照配置信息的传入方式
方法 | 描述 |
---|---|
build(InputStream inputStream【, String environment, Properties properties】) | inputStream是字节流,它封装了XML文件形式的配置信息 |
build(Reader reader【, String environment, Properties properties】) | Reader字符流封装了xml文件形式的配置信息 |
build(Configuration config) | Configuation对象用于封装MyBatis项目中的配置信息。 |
java
environment:决定将要加载的环境,包括数据源和事务管理器;
properties:决定将要加载的properties文件。
- 使用方式:
java
// 读取配置文件
InputStream inputStream = Resources.getResourceAsStream("配置文件位置");
// 根据配置文件构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSessionFactory对象是线程安全的,它一旦被创建,在整个应用程序执行期间都会存在,使用单例模式创建。
3.2 SqlSessionFactory对象
- **作用:**创建SqlSession对象
- 方法:
方法名称 | 描述 |
---|---|
SqlSession openSession() | 开启一个事务。 |
SqlSession openSession(Boolean autoCommit) | 参数autoCommit可设置是否开启事务。 (true表示关闭事务控制,自动提交;false表示开启事务控制。若不传入参数,默认为false。) |
SqlSession openSession(ExecutorType execType) | ExecutorType.SIMPLE:表示为每条语句创建一条新的预处理语句。ExecutorType.REUSE:表示会复用预处理语句。ExecutorType.BATCH:表示会批量执行所有更新语句。 |
3.3 SqlSession对象
- **作用:**SqlSession对象包含了执行SQL操作的方法,由于其底层封装了JDBC连接,所以可以直接使用SqlSession对象来执行已映射的SQL语句(单线程对象)。
- 注意: 每一个线程都应该有一个自己的SqlSession对象,并且该对象不能共享。SqlSession对象是线程不安全的,绝不能将其放在类的静态字段、对象字段或任何类型的管理范围中使用。SqlSession对象使用完之后,要及时的关闭。
- 方法:
有关SELECT相关的方法:
方法名称 | 描述 |
---|---|
T selectOne(String statement) | statement是在配置文件中定义的select元素的id。 |
T selectOne(String statement, Object parameter) | parameter是查询语句所需的参数。 |
List selectList(String statement) | statement是在配置文件中定义的select元素的id。 |
List selectList(String statement, Object | parameter是查询语句所需的参数。 |
List selectList(String statement, Object parameter, RowBounds rowBounds) | rowBounds是用于分页的参数对象。 |
void select(String statement, Object parameter, ResultHandler handler) | handler对象用于处理查询语句返回的复杂结果集。该方法多用于多表查询。 |
有关INSERT相关的方法:
方法名称 | 描述 |
---|---|
int insert(String statement) | 参数statement是在配置文件中定义的insert元素的id。 返回影响条数 |
int insert(String statement, Object parameter) | parameter是插入语句所需的参数。 |
有关UPDATE相关的方法:
方法名称 | 描述 |
---|---|
int update(String statement) | 参数statement是在配置文件中定义的update元素的id。 返回更新条数 |
int update(String statement, Object parameter) | parameter是更新语句所需的参数。 |
有关DELETE相关的方法:
方法名称 | 描述 |
---|---|
int delete(String statement) | 参数statement是在配置文件中定义的delete元素的id。返回影响条数 |
int delete(String statement, Object parameter) | parameter是删除语句所需的参数。 |
有关事务的相关的方法:
方法名称 | 描述 |
---|---|
void commit() | 提交事务的方法。 |
void rollback() | 回滚事务的方法。 |
void close() | 关闭SqlSession对象。 |
四、MyBatis核心配置文件
MyBatis核心配置文件配置了MyBatis的全局信息。
在核心配置文件中,<configuration>
的子元素必须按照上图由上到下的顺序进行配置,否则MyBatis在解析XML配置文件的时候会报错。
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>
<!-- 加载db.properties文件 -->
<properties resource="db.properties"/>
<!-- 设置别名 -->
<typeAliases>
<typeAlias alias="User" type="com.tyut.pojo.User"/>
</typeAliases>
<!-- 加载运行环境 -->
<environments default="development">
<environment id="development">
<!-- 事务管理 -->
<transactionManager type="JDBC"/>
<!-- 数据源管理 -->
<dataSource type="POOLED">
<property name="drive" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- 映射文件 -->
<mappers>
<mapper resource="com.tyut.mapper.UserMapper"></mapper>
</mappers>
</configuration>
4.1 <properties>
元素
<properties>
是一个配置属性的元素,该元素的作用是读取外部文件的配置信息
xml
<!-- 加载db.properties文件 -->
<properties resource="db.properties">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</properties>
xml
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db_01
jdbc.username=root
jdbc.password=root
4.2 <typeAliases>
元素
**作用:**使用<typeAliases>
元素为冗长的全限定名设置别名,简化代码书写。
**方式一:**在<typeAliases>
元素下,使用多个<typeAlias>
元素为每一个全限定类逐个配置别名。
xml
<typeAliases>
<typeAlias alias="User" type="com.tyut.pojo.User"/>
<typeAlias alias="Student" type="com.tyut.pojo.Student"/>
</typeAliases>
**方式二:**通过自动扫描包的形式自定义别名。
xml
<typeAliases>
<package name="com.itheima.pojo"/>
</typeAliases>
**方法三:**默认别名
4.3 <environments>
元素
**作用:**MyBatis可以配置多套运行环境,如开发环境、测试环境、生产环境等。MyBatis的运行环境信息包括事务管理器和数据源。
java
<transactionManager>元素用于配置运行环境的事务管理器;
<daraSource>元素用于配置运行环境的数据源信息。
java
<environments default="development">
<environment id="development">
<!---设置使用JDBC事务管理 -->
<transactionManager type="JDBC" />
<!-配置数据源 -->
<dataSource type="POOLED">
<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>
</environment>
</environments>
- 事务管理
java
<transcationManager>元素可以配置两种类型的事务管理器,分别是JDBC和MANAGED。
--JDBC:此配置直接使用JDBC的提交和回滚设置,它依赖于从数据源得到的连接来管理事务的作用域。
--MANAGED:此配置不提交或回滚一个连接,而是让容器来管理事务的整个生命周期。默认情况下,它会关闭连接。
- 数据源管理
1.UNPOOLED表示数据源为无连接池类型。配置此数据源类型后,程序在每次被请求时会打开和关闭数据库连接。
属性 | 说明 |
---|---|
driver | JDBC驱动的Java类的完全限定名 |
url | 数据库的URL地址 |
username | 登录数据库的用户名 |
password | 登录数据库的密码 |
defaultTransactionIsolationLevel | 默认的连接事务隔离级别 |
2.POOLED表示数据源为连接池类型。节省了在创建新的连接对象时需要初始化和认证的时间。
属性 | 说明 |
---|---|
poolMaximumActiveConnections | 在任意时间可以存在的活动连接数量,默认值:10。 |
poolMaximumIdleConnections | 任意时间可能存在的空闲连接数。 |
4.4 <mappers>
元素
作用: <mappers>
元素用于引入MyBatis映射文件。映射文件包含了POJO对象和数据表之间映射信息。MyBatis通过核心配置文件中的<mappers>
元素找到映射文件并解析其中的映射信息
xml
//类路径引入
<mappers>
<mapper resource="com/tyut/mapper/Mapper.xml"/>
</mappers>
//本地文件路径引入
<mappers>
<mapper url="file://D:/com/tyut/mapper/Mapper.xml"/>
</mappers>
//接口引入
<mappers>
<mapper class="com.tyut.mapper.Mapper"/>
</mappers>
//包名引入
<mappers>
<package name="com.tyut.mapper"/>
</mappers>
五、MyBatis映射文件
相关约束信息
xml
<?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">
1.mapper元素
- namespace属性
java
1.用于区分不同的mapper,全局唯一。
2.绑定DAO接口,即面向接口编程。当namespace绑定某一接口之后,可以不用写该接口的实现类,MyBatis会通过接口的全限定名查找到对应的mapper配置来执行SQL语句,因此namespace的命名必须跟接口同名。
- id属性
java
1.在不同的映射文件中,<mapper>元素的子元素的id可以相同。
2.MyBatis通过<mapper>元素的namespace属性值和子元素的id联合区分不同的Mapper.xml文件。
3.接口中的方法与映射文件中SQL语句id应一一对应。
2.select元素
<select>
元素用来映射查询语句,它可以从数据库中查询数据并返回。
xml
<select id="" parameterType="" resultType="">
select的sql语句
</select>
属性 | 说明 |
---|---|
id | 表示命名空间中元素的唯一标识,通过该标识可以调用这条查询语句。 |
parameterType | 它是一个可选属性,用于指定SQL语句所需参数类的全限定名 或者别名,其默认值是unset。 |
resultType | 用于指定执行这条SQL语句返回的全限定类名 或别名。 |
resultMap | 表示外部resultMap的命名引用。resultMap和resultType不能同时使用。 |
flushCache | 用于指定是否需要MyBatis清空本地缓存和二级缓存。 |
timeout | 用于设置超时时间,单位为秒。 |
3.insert元素
<insert>
元素用于映射插入语句,在执行完元素中定义的SQL语句后,会返回插入记录的数量。
xml
<insert id="" parameterType="">
insert into users(uid,uname,uage) values(#{uid}, #{uname}, #{uage})
</insert>
属性 | 说明 |
---|---|
keyProperty <仅对insert和update元素有用> | 将插入或更新操作的返回值赋值给POJO类的某属性。如果需要设置联合主键,在多个值之间用逗号隔开 |
keyColumn <仅对insert和update元素有用> | 该属性用于设置第几列是主键,当主键列不是表中的第一列时需要设置。需要设置联合主键时,在多个值之间用逗号隔开。 |
useGeneratedKeys <仅对insert和update元素有用> | 该属性会使MyBatis调用JDBC的getGeneratedKeys方法来获取由数据库内部生产的主键,如MySQL和SQL Server等自动递增的字段,其默认值为false。 |
如果使用的数据库支持主键自动增长,那么可以通过keyProperty属性指定POJO类的某个属性接收主键返回值(通常会设置到id属性上),然后useGeneratedKeys的属性值设置为true。
xml
<insert id="addUser" parameterType=""
keyProperty="uid" useGeneratedKeys="true" >
insert into users(uid,uname,uage) values(#{uid},#{uname},#{uage})
</insert>
4.update元素
<update>
元素用于映射更新语句,它可以更新数据库中的数据。在执行完元素中定义的SQL语句后,会返回更新的记录数量。
xml
<update id="" parameterType="">
update users set uname= #{uname},uage = #{uage} where uid = #{uid}
</update>
5.delete元素
<delete>
元素用于映射删除语句,在执行完<delete>
元素中的SQL语句之后,会返回删除的记录数量。
xml
<delete id="deleteUser" parameterType="Integer">
delete from users where uid=#{uid}
</delete>
6.sql元素
<sql>
元素的作用是定义可重用的SQL代码片段,它可以被包含在其他语句中。<sql>
元素可以被静态地(在加载参数时)参数化,<sql>
元素不同的属性值通过包含的对象发生变化。
xml
<sql id="someinclude">
from
<include refid="${include_target}" /></sql>
<sql id="userColumns">
uid,uname,uage
</sql>
<select id="findUserById" parameterType="Integer"
resultType="com.tyut.pojo.User">
select
<include refid="userColumns"/>
<include refid="someinclude">
<property name="include_target" value="users" />
</include>
where uid = #{uid}
</select>
tip: <sql>
标签对经常使用的代码段进行提取,在引用时要用到如下标签
xml
<include refid="sql标签的id">
<property name="sql标签中的占位符" value="占位符的值">
</include>
7.resultMap元素
<resultMap>
元素主要作用是定义映射规则、更新级联以及定义类型转化器等。
markdown
默认情况下,MyBatis程序在运行时会自动将查询到的数据与需返回的对象的属性进行匹配赋值(**数据表中列名**与**对象的属性**名完全一致才能匹配成功并赋值)。
数据表中的列和需要返回的对象的属性可能不会完全一致,这种情况下MyBatis不会自动赋值,这时就需要使用<resultMap>元素进行结果集映射。
xml
<mapper namespace="com.tyut.mapper.StudentMapper">
<resultMap type="要映射的pojo对象" id="sm">
<id property="属性名" column="db列名"/>
<result property="" column=""/>
</resultMap>
<select id="findAllStudent" resultMap="sm">
select * from t_student
</select>
</mapper>
六、动态SQL语句
6.1 条件查询操作
1.单条件判断
java
<if test="逻辑判断语句">
要拼接的SQL语句
</if>
java
//对username做非空判断
select * from t_user where 1=1
<if test="username != '' and username != null">
and username like concat('%', #{username}, '%')
</if>
2.多分支判断
java
<choose>
<when test="逻辑判断语句"></when>
<when test="逻辑判断语句"></when>
<otherwise></otherwise>
</choose>
java
select * from t_user where 1=1
<choose>
<when test="username != null">
and username = #{username}
</when>
<when test="job != null">
and job = #{job}
</when>
<otherwise>
and phone is not null
</otherwise>
</choose>
在映射文件中,编写的SQL后面加入了"where 1=1"的条件的话,既保证了where后面的条件成立,又避免了where后面第一个词是and或者or之类的关键字。如果将where后面的1=1去掉,这条拼接出的SQL语句是不正确
3.where,trim元素
<where>
会自动判断SQL语句,只有<where>
内的一个或多个条件成立时,才会在拼接SQL中加入where关键字,否则将不会添加;还会去除多余的"AND"或"OR"。
xml
select * from t_customer
<where>
<if test="username !=null and username !=''">
and username like concat('%',#{username}, '%')
</if>
<if test="jobs !=null and jobs !=''">
and jobs= #{jobs}
</if>
</where>
<trim>
的作用是去除和添加特殊的字符串。
属性 | 说明 |
---|---|
prefix | 指定给SQL语句增加的前缀 |
prefixOverrides | 指定SQL语句中要去掉的前缀字符串 |
suffix | 指定给SQL语句增加的后缀 |
suffixOverrides | 指定SQL语句中要去掉的后缀字符串 |
xml
select * from t_customer
<trim prefix="where" prefixOverrides="and">
<if test="username !=null and username !=''">
and username like concat('%',#{username}, '%')
</if>
<if test="jobs !=null and jobs !=''">
and jobs= #{jobs}
</if>
</trim>
4.foreach元素
foreach元素主要用于遍历,支持数组,list,或set接口的集合.
属性 | 说明 |
---|---|
item(必选) | 集合中每一个元素进行迭代时的别名 |
index | 在List和数组中,index是元素的序号,在Map中,index是元素的key。 |
open | 表示foreach语句代码的开始符号,一般和close=")"合用。常用在in条件语句中。该属性可选。 |
separator | 表示元素之间的分隔符。可选 |
close | 表示foreach语句代码的关闭符号,一般和open="("合用。常用在in条件语句中。该属性可选。 |
collection(必选) | 用于指定遍历参数的类型。注意,该属性必须指定,不同情况下,该属性的值是不一样的。(若参数是List,collection为list;若参数是数组,collection为array;若参数是Map,collection为Map的键) |
- 遍历数组(传参为数组)
xml
<select id="findByArray"
parameterType="java.util.Arrays"
resultType="com.tyut.pojo.Customer">
select * from t_customer where id in
<foreach item="id" index="index" collection="array"
open="(" separator="," close=")">
#{id}
</foreach>
</select>
- 遍历集合(传参为集合)
xml
<select id="findByList" parameterType="java.util.List"
resultType="com.tyut.pojo.Customer">
select * from t_customer where id in
<foreach item="id" index="index" collection="list"
open="(" separator="," close=")">
#{id}
</foreach>
</select>
- 遍历Map(传参为多个聚合类型)
xml
<select id="findByMap" parameterType="java.util.Map"
resultType="com.itheima.pojo.Customer">
select * from t_customer where jobs=#{jobs} and id in
<foreach item="roleMap" index="index" collection="id" open="(" separator="," close=")">
#{roleMap}
</foreach>
</select>
6.2 更新操作
<set>
元素主要用于更新操作,它可以在动态SQL语句前输出一个SET关键字,并将SQL语句中最后一个多余的逗号去除。
java
update t_customer
<set>
<if test="username !=null and username !=''">
username=#{username},
</if>
<if test="jobs !=null and jobs !=''">
jobs=#{jobs},
</if>
</set>
where id=#{id}
**tip:**在使用<set>
元素进行字段信息更新时,要确保传入的更新字段不能都为空。
七、MyBatis框架环境搭建
1.pom相关依赖
xml
<!-- 添加相关的依赖 -->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- mybatis相关依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<!-- mysql相关依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
</dependencies>
- 为了使得项目可以加载到此项目下的所有特殊文件
xml
<!-- 对于项目中的properties和xml结尾的文件均可加载 -->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
2.配置 MyBatis 环境
2.1 创建 mybatis-config.xml
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>
<properties resource="db.properties"/>
<environments default="development">
<environment id="development">
<transactionManager type="jdbc"></transactionManager>
<dataSource type="POOLED">
<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>
</environment>
</environments>
<mappers>
<mapper resource="mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
2.2 配置数据源
jdbc.driver = com.mysql.cj.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/db_student?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false
jdbc.username = root
jdbc.password = 123456
2.3 创建pojo实体
java
public class User {
private int id;
private String name;
private String email;
// Getters and setters
}
2.4 创建Mapper接口
java
public interface UserDaoImpl {
User getUserById(int id);
List<User> getAllUsers();
}
2.5 创建Mapper映射文件
xml
<?xml version="1.0" encoding="UTF-8" ?>
<mapper namespace="com.tyut.mapper.UserMapper">
<select id="getUserById" resultType="User">
SELECT id, name, email FROM users WHERE id = #{id}
</select>
<select id="getAllUsers" resultType="User">
SELECT id, name, email FROM users
</select>
</mapper>
2.6 配置 SqlSessionFactory
java
public class MyBatisUtil {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession();
}
}
2.7 使用 MyBatis 进行数据库操作
java
public class UserService {
public User getUserById(int id) {
try (SqlSession session = MyBatisUtil.getSqlSession()) {
UserMapper userMapper = session.getMapper(UserMapper.class);
return userMapper.getUserById(id);
}
}
public List<User> getAllUsers() {
try (SqlSession session = MyBatisUtil.getSqlSession()) {
UserMapper userMapper = session.getMapper(UserMapper.class);
return userMapper.getAllUsers();
}
}
}