JavaSSM框架-MyBatis 框架(一)
一、MyBatis 框架
1. MyBatis简介
1.1 MyBatis历史
MyBatis
最初是Apache的一个开源项目 iBatis,
2010年6月这个项目由Apache Software Foundation迁移到了Google Code。随着开发团队转投Google Code旗下, iBatis3.x正式更名为MyBatis
。代码于2013年11月迁移到Github。
iBatis一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架
。 iBatis提供的持久层框架包括SQL Maps 和Data Access Objects(DAO)。
1.2 MyBatis特性
-
MyBatis 是支持
定制化 SQL
,存储过程以及高级映射的优秀的持久层框架 -
MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集
-
MyBatis可以
使用简单的XML或注解用于配置和原始映射
,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录 -
MyBatis 是一个
半自动的ORM(Object Relation Mapping)
框架
1.3 MyBatis下载
MyBatis下载地址:https://github.com/mybatis/mybatis-3
1.4 和其它持久化层技术对比
- JDBC
- SQL 夹杂在Java代码中耦合度高,导致硬编码内伤
- 维护不易且实际开发需求中 SQL 有变化,频繁修改的情况多见
- 代码冗长,开发效率低
- Hibernate 和 JPA
- 操作简便,开发效率高
- 程序中的长难复杂 SQL 需要绕过框架
- 内部自动生产的 SQL,不容易做特殊优化
- 基于全映射的全自动框架,大量字段的 POJO 进行部分映射时比较困难。
- 反射操作太多,导致数据库性能下降
- MyBatis
- 轻量级,性能出色
- SQL 和 Java 编码分开,功能边界清晰。Java代码专注业务、SQL语句专注数据
- 开发效率稍逊于HIbernate,但是完全能够接受
2. 搭建使用MyBatis
2.1 创建Maven项目
-
开发环境
-
IDE:idea 2019.2
-
构建工具:maven 3.5.4
-
MySQL版本:MySQL 8
-
MyBatis版本:MyBatis 3.5.7
-
-
MySQL不同版本的注意事项
1、驱动类driver-class-name
MySQL 5版本使用jdbc5驱动,驱动类使用:com.mysql.jdbc.Driver
MySQL 8版本使用jdbc8驱动,驱动类使用:
com.mysql.cj.jdbc.Driver
2、连接地址url
MySQL 5版本的url:
jdbc:mysql://localhost:3306/ssm
,其中ssm
为要操作的数据库
MySQL 8版本的url:
jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
否则运行测试用例报告如下错误:
java.sql.SQLException: The server time zone value ‘Öйú±ê׼ʱ¼ä’ is unrecognized or represents more
-
创建Maven项目并导入相关依赖
<dependencies><!-- Mybatis核心 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.7</version></dependency><!-- junit测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- MySQL驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version></dependency> </dependencies>
-
创建
ssm数据库
,以及t_user
表create database ssm; CREATE TABLE `t_user` (`id` int PRIMARY KEY NOT NULL AUTO_INCREMENT,`username` varchar(20),`password` varchar(20),`age` int,`gender` char(1),`email` varchar(50), )
-
创建 User 类
在
pojo
包下创建User类,注意养成习惯,该类属于POJO类,因此创建一个包用来写POJO类package com.qingtian.mybatis.pojo;public class User {private Integer id;private String username;private String password;private Integer age;private String gender;private String email;public User() {}public User(Integer id, String username, String password, Integer age, String gender, String email) {this.id = id;this.username = username;this.password = password;this.age = age;this.gender = gender;this.email = email;}public Integer getId() { return id; }public void setId(Integer id) { this.id = id; }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 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 String getEmail() { return email; }public void setEmail(String email) { this.email = email; }@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +", age=" + age +", gender='" + gender + '\'' +", email='" + email + '\'' +'}';} }
2.2 创建MyBatis的核心配置文件
MyBatis有两个配置文件
,一个是核心配置文件
,一个是映射文件
,其中核心配置文件是用来配置相关信息的
,例如连接数据库等,而映射文件则是用来编写SQL语句的
核心配置文件:
-
该文件习惯上命名为
mybatis-config.xml
,这个文件名仅仅只是建议,并非强制要求。将来整合Spring 之后,这个配置文件可以省略,这里可以直接复制、粘贴。 -
核心配置文件主要用于
配置连接数据库的环境以及MyBatis的全局配置信息
,核心配置文件存放的位置是src/main/resources
目录下,其中maven项目的resource目录就是用来存放配置文件的
。 -
配置文件相关信息说明:
environment
标签:表示连接数据库的环境,即相关连接数据配置信息,如driver
用于配置驱动,url
配置要连接的数据库,其写法与使用jdbc的properties
配置文件一致,前面的name
属性的名不能改,直接改value
即可mapper
标签:用来引入映射文件的,每写一个映射文件都要从这里引入,要不然不会生效
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//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="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC"/><property name="username" value="root"/><property name="password" value="123456"/></dataSource></environment></environments> <!--引入映射文件--> <mappers><!--resource = 映射文件路径--><mapper resource="mappers/UserMapper.xml"/> </mappers></configuration>
2.3 创建mapper接口
MyBatis中的mapper接口相当于以前的dao
。但是区别在于,mapper仅仅是接口,我们不需要提供实现类。
DAO是针对某个数据库中的表实现的一个类,该类用于对该表进行CRUD操作的类,一个表对应一个POJO,对应一个DAO
。同样,使用MyBatis框架
时,一个表对应一个POJO,对应一个Mapper接口
,以t_user
表为例,其对应的POJO类
命名为User
,对应的Mapper接口
命名为UserMapper
,接口里面定义的方法即用来实现CRUD操作的,因此命名也要规范
package com.qingtian.mybatis.mapper;public interface UserMapper {/*** 添加用户信息*/int insertUser();
}
2.4 创建MyBatis的映射文件
相关概念:ORM(Object Relationship Mapping)对象关系映射
。
- 对象:Java的实体类对象
- 关系:关系型数据库
- 映射:二者之间的对应关系
Java概念 | 数据库概念 |
---|---|
类 | 表 |
属性 | 字段/列 |
对象 | 记录/行 |
1、映射文件的命名规则:表所对应的实体类的类名+Mapper.xml
例如:表t_user,映射的实体类为User,所对应的映射文件为UserMapper.xml
因此一个映射文件对应一个实体类
,对应一张表的操作
,对应一个接口
,例如User类,UserMapper接口与UserMapper.xml映射文件
MyBatis映射文件用于编写SQL,访问以及操作表中的数据 MyBatis映射文件存放的位置是src/main/resources/mappers
目录下,mappers
专门用于存放映射文件,因为一张表对应一个映射文件,所以会有多个映射文件
2、 MyBatis中可以面向接口操作数据,要保证两个一致
: mapper接口的全类名
和映射文件的命名空间(namespace)
保持一致 mapper接口中方法的方法名
和映射文件中编写SQL的标签的id属性
保持一致
3、记得将映射文件引入到MyBatis核心配置文件中
MyBatis映射文件如下:
其中com.atguigu.mybatis.mapper.UserMapper
与UserMapper
接口全类名保持一致,而insert
标签的id
与UserMapper
接口中的inserUser
方法名保持一致。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.mybatis.mapper.UserMapper"><!--int insertUser();--><insert id="insertUser">insert into t_user values(null,'admin','123456',23,'男','12345@qq.com')</insert>
</mapper>
2.5 通过junit测试功能
public class MyBatisTest {@Testpublic void testInsert() throws IOException {//读取MyBatis的核心配置文件InputStream is = Resources.getResourceAsStream("mybatis-config.xml");//创建SqlSessionFactoryBuilder对象SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();//通过核心配置文件所对应的字节输入流创建工厂类SqlSessionFactory,生产SqlSession对象SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);//创建SqlSession对象,此时通过SqlSession对象所操作的sql都必须手动提交或回滚事务//SqlSession sqlSession = sqlSessionFactory.openSession();//创建SqlSession对象,此时通过SqlSession对象所操作的sql都会自动提交SqlSession sqlSession = sqlSessionFactory.openSession(true);//通过代理模式创建UserMapper接口的代理实现类对象UserMapper userMapper = sqlSession.getMapper(UserMapper.class);//调用UserMapper接口中的方法,就可以根据UserMapper的全类名匹配元素文件,通过调用的方法名匹配//映射文件中的SQL标签,并执行标签中的SQL语句int result = userMapper.insertUser();//提供sql以及的唯一标识找到sql并执行,唯一标识是 namespace.sqlId,这是原始的mybatis//执行sql的情况//int result = // sqlSession.insert("com.atguigu.mybatis.mapper.UserMapper.insertuser");//sqlSession.commit();System.out.println("结果:"+result);}
}
SqlSession
:代表Java程序和数据库之间的会话。(HttpSession是Java程序和浏览器之间的会话)SqlSessionFactory
:是生产SqlSession的工厂。工厂模式
:如果创建某一个对象,使用的过程基本固定,那么我们就可以把创建这个对象的相关代码封装到一个“工厂类”中,以后都使用这个工厂类来“生产”我们需要的对象。- 注意:
不要导错包了
,Resources
等类都是MyBatis提供
的Resources所在包:org.apache.ibatis.io
SqlSession,SqlSessionFactory,SqlSessionFactoryBuilder所在包:org.apache.ibatis.session
MyBatis执行SQL的步骤:
- 首先
读取MyBatis配置文件作为输入流
- 创建
SqlSessionFactoryBuilder
对象,并通过该对象build方法创建一个SqlSessionFactory
对象,最后由SqlSessionFactory
对象openSession方法创建一个SqlSession
对象,该对象用于执行SQL语句 - 利用SqlSession对象的getMapper方法通过代理模式创建UserMapper接口的代理实现类对象(
因为UserMapper本身为一个接口,不能实例化对象,所以需要通过代理模式,创建一个代理实现类对象
) - 然后利用UserMapper对象执行接口中定义的相关方法
调用接口中的方法后的执行流程:调用userMapper.insertUser();
方法后,首先通过UserMapper
接口找到对应的映射文件,然后再通过方法名insertUser
找到对应id
的标签,最后执行里面的SQL语句,如下是映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.mybatis.mapper.UserMapper"><!--int insertUser();--><insert id="insertUser">insert into t_user values(null,'admin','123456',23,'男','12345@qq.com')</insert>
</mapper>
2.6 加入log4j日志功能
-
加入依赖
<!-- log4j日志 --> <dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version> </dependency>
-
加入log4j的配置文件
log4j的配置文件名为log4j.xml,存放的位置是src/main/resources目录下
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"><appender name="STDOUT" class="org.apache.log4j.ConsoleAppender"><param name="Encoding" value="UTF-8" /><layout class="org.apache.log4j.PatternLayout"><param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS}%m (%F:%L) \n" /></layout></appender><logger name="java.sql"><level value="debug" /></logger><logger name="org.apache.ibatis"><level value="info" /></logger><root><level value="debug" /><appender-ref ref="STDOUT" /></root> </log4j:configuration>
日志的级别
FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试)
从左到右打印的内容越来越详细,即设置的为INFO级别,那么FATAL,ERROR,WAGN等信息也会被打印出来,如果设置的级别为ERROR,那只是会打印FATAL与ERROR等信息
3. MyBatis的增删改查
UserMapper接口
package com.qingtian.mybatis.mapper;import com.qingtian.mybatis.pojo.User;
import java.util.List;public interface UserMapper {int insertUser();int updateUser();int deleteUser();User getUserById();List<User> getAllUser();
}
MyBatis映射文件UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qingtian.mybatis.mapper.UserMapper">
<!-- int insertUser();--><insert id="insertUser">insert into t_user values(null,'admin','123456',23,'男','12345@qq.com')</insert><!-- int updateUser();--><update id="updateUser">update t_user set username = 'jack' where id = 4</update><!-- int deleteUser();--><delete id="deleteUser">delete from t_user where id = 7</delete><!-- User getUserById();--><select id="getUserById" resultType="com.qingtian.mybatis.pojo.User">select * from t_user where id = 4</select><!-- List<User> getAllUser();--><select id="getAllUser" resultType="com.qingtian.mybatis.pojo.User">select * from t_user</select></mapper>
注意:
在执行select操作时,select标签必须设置属性resultType或resultMap的其中一个,且只能设置一个
,用于设置实体类和数据库表的映射,即要查询的这张表对应的哪个POJO类
,设置该类的全类名
resultType
:自动映射,用于POJO类中属性名
和数据库表中字段名一致
的情况
resultMap
:自定义映射,用于一对多或多对一
或字段名和属性名不一致
的情况
利用SqlSession封装的Util
注意在写SqlSessionUtil
时,最好捕获异常,因为Resources.getResourceAsStream()
抛出的异常是一个编译异常,必须要处理的,如果是抛出的话,那在其调用的地方,也得处理这个编译异常,不如直接捕获,然后在catch
里throw new RuntimeException(e)
,将其变成一个运行异常(常用方法)
package com.qingtian.mybatis.utils;
public class SqlSessionUtil {public static SqlSession getSqlSession() {SqlSession sqlSession = null;try {InputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);sqlSession = sqlSessionFactory.openSession(true);} catch (IOException e) {e.printStackTrace();throw new RuntimeException(e);}return sqlSession;}
}
Maven项目test包下的MyBatisTest
public class MyBatisTest {@Testpublic void testInsert() throws IOException {InputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);SqlSession sqlSession = sqlSessionFactory.openSession(true);UserMapper mapper = sqlSession.getMapper(UserMapper.class);int res = mapper.insertUser();System.out.println("result: " + res);
// sqlSession.commit();sqlSession.close();}@Testpublic void testUpdate() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);mapper.updateUser();sqlSession.close();}@Testpublic void testDelete() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);mapper.deleteUser();sqlSession.close();}@Testpublic void testGetUserById() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User userById = mapper.getUserById();System.out.println(userById);}@Testpublic void testGetAllUser() {SqlSession sqlSession = SqlSessionUtil.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> allUser = mapper.getAllUser();for (User user : allUser) {System.out.println(user);}}
}
课程链接:https://www.bilibili.com/video/BV1Ya411S7aT