环境
- JDK 1.8
- MySQL 8.0
- Maven 3.6.3
- IntelliJ IDEA 2020
知识
- JDBC
- MySQL
- Java基础
- Maven
- JUnit
1、简介
1.1、什么是MyBatis
- 基于Java的持久层框架;
- 支持自定义 SQL、存储过程以及高级映射;
- 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作;
- 可以通过简单的 XML 或注解来配置和映射原生类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
- 本是apache的一个开源项目iBatis,2010年由apache software foundation 迁移到了google code,改名为MyBatis 。2013年11月迁移到Github。
获得MyBatis
-
W3C school:https://www.w3cschool.cn/mybatis/
-
Maven仓库:https://mvnrepository.com/artifact/org.mybatis/mybatis`
1.2、持久化
数据持久化
- 包括和数据库相关的各种操作(保存、更新、删除、加载、查询)
内存中的数据模型
和存储模型
之间的相互转换;
优点
-
代码重用性强:即使更换数据库,只需要更改配置文件,不必重写程序代码。
-
代码可读性强:在代码中不会有大量的SQL语言,提高程序的可读性。
-
缓存:持久化技术可以自动优化,以减少对数据库的访问量,提高程序运行效率。
持久层
- 完成持久化工作的代码块。
1.3、为什么需要MyBatis
- 简单易学,没有任何第三方依赖;
- 灵活:SQL写在xml里,便于统一管理和优化;
- SQL和代码分离,提高了可维护性;
- 提供映射标签,支持对象与数据库的ORM字段关系映射;
- 提供对象关系映射标签,支持对象关系组建维护;
- 提供xml标签,支持编写动态sql。
2、入门:第一个MyBatis
2.1、搭建环境
创建数据库
搭建项目
- 新建一个不带模板的Maven项目;
- 删除src目录,将该工程作为项目的父工程;
- 导入Maven依赖:
<dependencies>
<!-- 数据库连接 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!--JUnit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
2.2、创建模块
在父工程下新建Module
,作为父工程的子模块。
MyBatis配置文件
mybatis-config.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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="数据库驱动"/>
<property name="url" value="数据库URL?参数"/>
<property name="username" value="用户名"/>
<property name="password" value="密码"/>
</dataSource>
</environment>
</environments>
<!-- 如果Mapper.xml等配置文件不在resources目录下,需要注册,注意用/分隔 -->
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
MyBatis工具类
-
用于构建
SqlSessionFactory
,从而创建构建SqlSession
实例。 -
SqlSession
相当于JDBC中的PreparedStatement
,提供了数据库执行 SQL 命令所需的方法。
注意:sqlSessionFactory
提升作用域后,如果静态代码块中的sqlSessionFactory
重新声明,最高级作用域
(代码块外面的)的sqlSessionFactory
没有赋值,会报NPE。
public class MyBatisUtils {
static SqlSessionFactory sqlSessionFactory;
// 从XML中构建SqlSessionFactory
static {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 错误写法,报NPE: SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取SqlSession实例
*
* @return SqlSession实例
*/
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession();
}
}*
* @return SqlSession实例
*/
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession();
}
}
2.3、编写代码
实体类
ORM原则
/**
* ID:数据库字段自动生成,无需手动设置
*/
private Long id;
/**
* 名称
*/
private String name;
/**
* 密码
*/
private String password;
DAO
- 通常用
Mapper
表示,UserMapper
即原来的UserDAO
。
public interface UserMapper {
/**
* 查询所有用户
*
* @return 用户列表
*/
List<User> listUsers();
}
DAO实现
-
使用
Mapper.xml
配置文件,代替原来的DAOImpl
。 -
通常与接口放在一起,写完要去
MyBatis配置文件
中注册。
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 映射:接口绑定,相当于实现接口 -->
<mapper namespace="indi.jaywee.dao.UserMapper">
<!--
相当于重写方法
id:重写的方法名;
resultType:返回结果类型,全类名
-->
<select id="listUsers" resultType="indi.jaywee.pojo.User">
select * from mybatis.user
</select>
</mapper>
2.4、JUnit测试
public class UserMapperTest {
@Test
public void testListUsers(){
// 获取SqlSession实例
SqlSession sqlSession = MyBatisUtils.getSqlSession();
// 获取Mapper
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 执行方法
List<User> users = mapper.listUsers();
for (User user : users) {
System.out.println(user);
}
// 关闭连接
sqlSession.close();
}
}
2.5、常见报错
java.lang.NullPointerException at indi.jaywee.utils.MyBatisUtils.getSqlSession
- 错误:sqlSessionFactory是空值,调用getSqlSession()自然就会报空指针。
- 解决:查看工具类
MyBatisUtils
的静态代码中的SqlSessionFactory
,将声明去掉。
static SqlSessionFactory sqlSessionFactory;
// 从XML中构建SqlSessionFactory
static {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 错误写法:SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
java.io.IOException
:Could not find resource resources/mybatis-config.xml
-
错误:找不到
MyBatis的配置文件
,说明工具类中的resource
路径有误。 -
解决:查看工具类
MyBatisUtils
中的resource变量值,修改为正确路径。
org.apache.ibatis.binding.BindingException
:Type interface indi.jaywee.dao.UserMapper is not known to the MapperRegistry.
- 错误:Mapper没有注册。
- 解决:在MyBatis的配置文件中注册,注意路径之间是用
/
分隔,否则也会报错。
<mappers>
<mapper resource="indi/jaywee/dao/UserMapper.xml"></mapper>
</mappers>
java.lang.ExceptionInInitializerError
-
错误:初始化失败,找不到Mapper.xml配置文件。
-
说明:
- 标准的Maven项目都有
resources目录
来存放资源配置文件
。Maven项目构建编译时,默认只会把resources目录下的资源配置文件导出到target目录
中,而不会将其他目录下的资源配置文件导出。 - 在实际项目中,可能会把资源配置文件放在resources以外的位置。如MyBatis框架中一般把Mapper.xml和接口类放在一起。这些资源配置文件不会被导出到target文件夹,导致资源配置文件读取失败。
- 标准的Maven项目都有
-
解决:在项目的
pom.xml
中设置过滤
,最好在每个新建的Maven项目都设置。
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
无效的2字节、3字节等问题
- 编码问题:IDEA默认使用
GBK
对资源配置文件编码,而以上使用到的xml文件
都是以UTF-8
编码。在这个情况下,如果在xml文件中使用了中文注释会报此异常。 - 解决:将IDEA的资源配置文件的字符编码集设为UTF-8。
- 注意:跟修改Maven一样,只要是IDEA中修改设置,需要在进入项目前的小窗口设置,同时在进入项目后的设置中确认是否修改成功。
在完成项目模块的搭建之后,实体类
、工具类
和MyBatis配置文件
一般不用变动,只需在Mapper接口
和对应的Mapper.xml
配置文件中编写代码。