MyBatis学习与问题总结
MyBatis
为什么要学习MyBatis?
首先了解JDBC:
JDBC是Java程序实现访问数据库的基础,提供了一套数据库操作API
JDBC实现数据库操作得步骤:
- 加载驱动
- 获取连接
- 获取连接、执行者对象等
- 发送SQL语句等
操作比较繁琐,并且有一定局限性。劣势主要有:
- 频繁的创建、释放数据库连接会造成系统资源的浪费,影响系统性能
- 代码中的语句硬编码,会造成代码不易于维护,频繁修改SQL,违反开闭原则
- 使用PreparedStatment向占位符传参数存在硬编码,因为SQL where条件不确定,也许有修改需求,不易维护
- JDBC对结果及解析存在硬编码(查询列名),SQL变化导致解析代码变化,不易维护
解决方案:使用ORM框架完成数据库的编程操作。常用的ORM框架MyBatis,Hibernate。
MyBatis:支持普通SQL查询、存储及高级映射的持久层框架,几乎消除了JDBC冗余代码,无需手动设置参数和对结果集进行检索,使用简单的XML或注解进行配置和原始映射,将接口和Java的POJO映射成数据库中的记录,使工作人员可以使用面向对象的编程思想来操作数据库。
ORM框架:为了解决面向对象与关系型数据库中数据类型不匹配的技术,通过描述Java对象与数据库表之间的映射关系,自动将Java应用程序对象持久化到关系型数据库对应表中。
开发者只需关注SQL本身,不需要花精力 注册驱动、创建Connection对象、创建Statement对象、手动设置参数结果集检索等JDBC繁杂的过程代码。
MyBatis环境搭建以及测试
1. 创建Maven工程(IDEA)
2. 引入相关依赖(pom.xml)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>mybatis-test</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- Alt + Inster dependecy Serach查询依赖,也可以上Maven中央仓库找 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
4. 创建数据库连接配置(需在 src/main/resources 目录下创建db.properties)
mysql.driver=com.mysql.cj.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/test?serverTimezone=UTC&\
characterEncoding=utf8&useUnicode=true&useSSL=false
mysql.username=root
mysql.password=123456
5. 创建MyBatis核心配置文件(需在 src/main/resources 目录下创建mybatis-config.xml,可根据情况命名)
<?xml version="1.0" encoding="UTF-8" ?>
<!--上面的必须要写在第一行,否则报错-->
<!--创建MyBatis的核心配置文件-->
<!--注意路径 config-->
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Mapper 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"/>
<!-- 数据库连接相关配置,db.properties文件中的内容 -->
<dataSource type="POOLED">
<!-- <property name="driver" value="com.mysql.cj.jdbc.Driver"/>-->
<!-- <property name="url" value="jdbc:mysql://localhost:3306/test?serverTimezone=UTC"/>-->
<!-- <property name="username" value="root"/>-->
<!-- <property name="password" value="123456"/>-->
<property name="driver" value="${mysql.driver}"/>
<property name="url" value="${mysql.url}"/>
<property name="username" value="${mysql.username}"/>
<property name="password" value="${mysql.password}"/>
</dataSource>
</environment>
</environments>
<!--引入mybatis的映射文件-->
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>
6. 创建表(数据准备)
7. 创建POJO实体
8. 创建映射文件POJOMapper.xml(POJO对应的实体bean名称)
src/main/resources 文件下创建mapper文件夹,SQL语句与Java对象的关系映射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">
<!--
mapper为映射的根节点,namespace指定Dao接口完整类名
mybatis会根据这个接口动态创建一个实现类去实现这个接口,
而这个实现类是mapper的对象
-->
<mapper namespace="org.chiyu.pojo.User">
<!--
id = "接口中的方法名"
parameterType = "传入参数类型"
resultType="返回的实体对象,使用包.类名">
-->
<select id="findById" parameterType="Integer"
resultType="org.chiyu.pojo.User">
SELECT *
FROM users
where uid = #{id}
</select>
</mapper>
9.修改mybatis.config.xml配置文件射文件的路径加载到程序中)
添加映射文件路径配置,将映射文件的路径加载到程序中
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
10. 编写测试类
public class UserTest {
@Test
public void userFindByIdTest(){
String resources = "mybatis-config.xml";
//创建字符流
Reader reader = null;
try {
//读取mybatis-config.xml文件内容到reader对象中
reader = Resources.getResourceAsReader(resources);
} catch (IOException e) {
e.printStackTrace();
}
//初始化MyBatis数据库,创建SqlSessionFactory类的实例
SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder().build(reader);
//创建SqlSession实例
SqlSession session = sqlMapper.openSession();
//传入参数查询,返回结果
User user = session.selectOne("findById",1);
//输出结果
System.out.print(user.getUname());
//关闭session
session.close();
}
}
后续改动
public class MyBatisUtils {
private static SqlSessionFactory sqlSessionFactory = null;
//初始化SqlSessionFactory对象,静态代码块
//todo resource mybatis-config.xml配置文件信息 是否可以使用动态配置
static {
try {
//使用MyBatis提供的Resources的类加载MyBatis的配置文件
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
//构建SqlSessionFactory工厂
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
}
}
//获取SqlSession对象的静态方法
public static SqlSession getSession() {
return sqlSessionFactory.openSession();
}
10. MyBatis工作原理
(1) mybatis-config.xml 主要配置mybatis运行时环境
(2)mapper.xml SQL映射文件,配置SQL语句,需要再mybatis-config.xml配置才能执行;mybatis-conifg.xml可以配置多个映射文件,每个映射文件对应数据库的一张表
(3)通过MyBatis的环境等配置信息构建会化工厂SqlSessionFactory,用于创建SqlSession
(4)创建会话对象:SqlSessionFactory创建SqlSession对象,该对象包含了执行SQL语句的所有方法
(5)创建执行器:会话本身不能直接操作数据库,MyBatis底层定义一个Executor接口用于操作数据库,执行器会根据SqlSession传递的藏书动态生成需要执行的SQL语句,同时负责查询缓存地维护
(6)封装SQL信息:SqlSession内部通过执行器Executor操作数据库,执行器将待处理的SQL信息封装到MapperStatement对象中,MappedStatement对象中存储了要映射的SQL语句的id、参数等。Mapper.xml文件中一个SQL语句对应一个MapperedStatement对象,SQL语句的id即是MappedStatementid。Executor执行器会在执行SQL语句之前,通过MappedStatement将输入的参数映射到SQL语句中。
(7)操作数据库:根据动态生成的SQL操作数据库
(8)输出结果映射集:执行SQL语句之后,通过MappedStatement对象将输出结果映射至Java对象中。
mybatis核心配置
1. 三个核心对象
SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession
MyBatis以SqlSessionFactoryBuilder为中心
SqlSessionFactoryBuilder是SqlSessionFactory的构造者,通过重载的builder()方法构建SqlSessionFactory对象
1.1 SqlSessionFactoryBuilder
形式一:
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties)
InputStream字节流封装了XML文件形式的配置信息;参数environment和properties是可选参数
environment:用于指定要加载的环境,包括数据源和事务管理器
properties:用于指定要加载的properties文件
形式二:
public SqlSessionFactory build(Reader reader, String environment, Properties properties)
与上一种方法形式基本相同,区别是该方法使用了Reader字符流封装了XML配置文件信息
形式三:
public SqlSessionFactory build(Configuration config)
Configuration对象用于封装MyBatis项目中的配置信息
通过读取XML配置文件里的的方式来构建SqlSessionFactory对象
//读取配置配置文件,创建字节流
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//根据配置文件构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
1.2 SqlSessionFactory
用于创建SqlSession
是MyBaits的中心
在SqlSessionFactoryBuilder创建完SqlSessionFactory 对象后,SqlSessionFactory 就可以调用opeanSession()对象
方法 | 描述 |
---|---|
SqlSession openSession(); | 开启一个事务,连接对象从活动环境配置的数据源对象中得到,事务隔离界别将会使用驱动或数据源的默认设置,预处理语句不会复用,也不会批量处理更新 |
SqlSession openSession(boolean autoCommit); | autoCommit设置是否开启事务,true表示关闭事务控制(默认,自动提交);false开启事务控制 |
SqlSession openSession(Connection connection); | connection可以提供自定义连接 |
SqlSession openSession(TransactionIsolationLevel level); | level设置隔离级别 |
SqlSession openSession(ExecutorType execType); | execType为执行器的类型,3个可选类型:ExecutorType .SIMPLE表示每条语句创建一条新的预处理语句;ExecutorType.REUSE表示会复用预处理语句;ExecutorType .BATCH |
SqlSession openSession(ExecutorType execType, boolean autoCommit); | ExecutorType 执行器类型;autoCommit是否开启事务 |
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level); | ExecutorType 执行器类型;level设置隔离级别 |
SqlSession openSession(ExecutorType execType, Connection connection); | ExecutorType 执行器类型;connection可以提供自定义连接 |
1.3 SqlSession
是应用程序与持久层之间执行交互操作的对象,主要作用是执行持久化操作,类似于JDBC中Connection。SqlSession对象包含了执行SQL操作的方法,由于其底层封装了JDBC连接,所以可以使用SqlSession对象来执行已映射的SQL语句。
方法 | 描述 |
---|---|
T selectOne(String statement); | 查询方法,参数statement是在配置文件中定义的元素的id,该方法会返回SQL语句查询结果的一个泛型对象 |
T selectOne(String statement, Object parameter); | parameter是查询语句所需的参数。该方法会返回SQL语句查询结果的一个泛型对象 |
List selectList(String statement); | 该方法会返回SQL语句查询结果的一个泛型集合 |
List selectList(String statement, Object parameter); | |
List selectList(String statement, Object parameter, RowBounds rowBounds); | RowBounds 用于分页的参数对象。 |
<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey); | |
<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey); | |
<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds); | |
Cursor selectCursor(String statement); | |
Cursor selectCursor(String statement, Object parameter); | – |
Cursor selectCursor(String statement, Object parameter, RowBounds rowBounds); | |
void select(String statement, Object parameter, ResultHandler handler); | 插入方法,该方法返回执行SQL语句所影响的行数 |
void select(String statement, ResultHandler handler); | – |
void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler); | |
int insert(String statement); | 插入方法 |
int insert(String statement, Object parameter); | – |
int update(String statement); | 更新方法 |
int update(String statement, Object parameter); | |
int delete(String statement); | 删除方法 |
int delete(String statement, Object parameter); | |
void commit(); | 提交事务方法 |
void commit(boolean force); | |
void rollback(); | 回滚事务方法 |
void rollback(boolean force); | |
List flushStatements(); | – |
void close(); | |
void clearCache(); | |
Configuration getConfiguration(); | – |
T getMapper(Class type); | 会返回Mapper接口的代理对象,该对象关联了SqlSession对象,可以使用该对象直接调用相应方法操作数据库;type是Mapper接口的类型。官方推荐通过Mapper对象访问MyBatis |
Connection getConnection(); | 获取JDBC数据连接对象的方法 |
2. MyBatis核心配置文件
主要配置了MyBatis的一些全局信息
数据库连接信息、MyBatis运行时所需的特性,以及设置和影响MyBatis行为的一些属性。
配置文件编写后也不会轻易改动
2.1 配置文件的主要元素
MyBatis核心配置元素子元素,的子元素必须按照由上到下顺序配置,否则MyBatis在解析XML配置文件的时候会报错。
2.2 < proprties >
配置属性元素,读取外部文件的配置信息
如db.properties,配置了MyBatis的数据库连接配置
mysql.driver=com.mysql.cj.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/test?serverTimezone=UTC&\
characterEncoding=utf8&useUnicode=true&useSSL=false
mysql.username=root
mysql.password=123456
读取外部配置信息
<properties resource="db.properties"/>
引入db.properties文件后,如果希望动态获取db.properties文件中的数据库链接信息,可以使用< property>元素配置,属性值根据db.properties中数据的配置动态改变
<dataSource type="POOLED">
<property name="driver" value="${mysql.driver}"/>
<property name="url" value="${mysql.url}"/>
<property name="username" value="${mysql.username}"/>
<property name="password" value="${mysql.password}"/>
</dataSource>
2.3 < settings>
用于改变MyBatis运行时的行为,如何开启二级缓存、开启延时加载等。
配置参数 | 描述 | 有效值 | 默认值 |
---|---|---|---|
2.4 < typeAliases>
为POJO起简短的别名,防止容易出现拼写上的错误(觉得用处不大)
2.5 < environments>
- MyBatis可以配置多套的配置环境,如开发环境、测试环境、生产环境等,可以灵活,从而将SQL映射到不同运行环境的数据库中。该标签来配置不同的运行环境,但不论增加了几套运行环境,都必须要明确选择当前要用的唯一的一个运行环境。
- MyBatis运行环境信息包括事务管理器和数据源。
- 子标签:
< teansactionManager>用于配置运行环境的事务管理器,type = “”:
JDBC:此配置直接使用JDBC的提交和回滚,它依赖于从数据源得到的连接来管理事务的作用域
MANAGED:此配置不提交或回滚一个连接,而是让容器来管理事务的整个声明周期。默认情况下,它会关闭连接,但有些容器并不希望这样,为此可以将< transactionManager>元素的closeConnection属性设置为false来阻止它默认的关闭行为。
< dataSource>用于配置运行环境的数据原信息
如果Spring+MyBatis的项目,则没有必要再MyBatis中配置事务管理器,因为实际开发中项目会使用Spring自带的管理器来实现事务管理。
对于数据源的配置,MyBatis提供了UNPLLDED、POOLED和JNDI 3种数据源类型:
- UNPOOLED
表示书院为无连接池类型。配置此数据源类型后,程序在每次被请求时会打开和关闭数据库连接。适用于对于性能不高的简单应用程序
需要配置的5种属性
属性 | 说明 |
---|---|
driver | JDBC驱动的Java类的完全限定名(并不是JDBC驱动中可能包含的数据源类) |
url | 数据库的URL地址 |
username | 登录数据库的用户名 |
password | 登录数据库的密码 |
defaultTransactionIsolationLevel | 默认的连接事务隔离级别 |
- POOLED(合并的)
表示数据源为连接池类型。POOLED数据源利用“池”的概念将JDBC连接对象组织起来,节省了创建新的链接对象时需要初始化和认证的时间。POOLED使并发Web应用可以快速响应请求,是当前比较流行的数据源配置类型。
POOLED出了UNPOOLED的5种属性外,还可以配置更多属性
属性 | 说明 |
---|---|
poolMaximumActiveConnections | 在任意时间可以存在的活动(也就是正在使用)连接数量,默认是10 |
poolMaxinumdleConnections | 任意时间可能存在的空闲连接数 |
poolMaximumCheckoutTime | 在被强制返回前,池中连接被检测出(check out)时间,默认值为20000毫秒,即20秒 |
poolTimeToWait | 如果获取连接花费时间较长,它会给连接池打印状态日志并重新尝试获取一个连接(避免在错误配置的情况下一直处于无提示的失败),默认值为20000毫秒,即20秒 |
poolPingQuery | 发送到数据库的侦测查询,用于检测连接是否处于正常工作秩序中,默认值是“NO PING QUERY SET” |
poolPingEnabled | 是否启用侦测查询,若开启,则必须使用一个可执行的SQL语句(最好是一个非常快的SQL)设置poolPingEnabled 属性,默认值为false |
poolPingCommectionsNotUsedFor | 配置poolPingQuery的使用频度,该属性的值可以被设置成匹配具体的数据库连接超时时间,从而避免不必要的侦测,默认值为0(表示所有连接每一时刻都被侦测),只有poolPingEnable的属性值为true时适用 |
- JNDI
- 代办
2.6 < mappers>
MyBatis核心配置文件中,该元素用于引入MyBatis映射文件。映射文件包括POJO对象和数据表之间的映射信息,MyBatis核心配置文件找到映射文件并解析映射信息。
引入映射文件4种方式:
- 类路径引入
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
- 本地文件路径引入
<mappers>
<mapper url="file:///D:/PersonalFiles/Learn/AboutJava/Base/mybatis-test/src/main/resources/mapper/UserMapper.xml"/>
</mappers>
- 接口引入
- 包名引入
3. MyBatis映射文件
MyBatis专注于SQL语句
常用元素:
元素 | 说明 |
---|---|
mapper | 映射文件根元素,<>只有namespace(命名空间)属性:区分不同的mapper,全局唯一;绑定DAO接口,即面向接口编程。当namespace绑定某一接口的实现类,MyBatis会通过接口的全限定类名查找到对应的mapper配置来执行SQL语句,因此namespace的命名必须跟接口同名 |
cache | 配置给定命名空间的缓存 |
cache-ref | 从其他命名空间引用缓存配置 |
select | 用于映射查询语句 |
insert | 用于映射插入语句 |
update | |
delete | |
sql | 可以重用的SQL块,也可以被其他语句使用 |
resultMap | 描述数据库结果集和对象的对应关系,告诉表字段对应对象的哪个属性(column —property) |
3.1 select
- 补充元素属性
3.2 insert
- 补充元素属性
3.3 update
- 补充元素属性