MyBatisJava 持久层框架入门与实践 | 学习笔记
Posted Fxtack
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatisJava 持久层框架入门与实践 | 学习笔记相关的知识,希望对你有一定的参考价值。
Java 持久层框架入门与实践 | 学习笔记
导读
本篇文章将带领读者学习 MyBatis 框架。开始文章简述 MyBatis。之后将手把手的搭建一个简单的 MyBatis 框架的测试,先跑起来。随后将基于该测试讲解 MyBatis 框架中重要的几个配置文件。然后对于数据库常用的增、删、查、改操作在 MyBatis 中的进行实现,并讨论一些 Java 中集合在 MyBatis 中的配置与应用。剩下的时间将讲解一些细节而常用的知识。
文中代码中嵌有大量的注释,这些注释对于理解和学习 MyBatis 有巨大的作用,请不要因为页面显示的字体颜色不清晰而忽略掉它们。
文中的测试与运行环境为:Java 8,IDEA 2020,Maven3.6.1,MyBatis 3.4.6,mysql 8.0.15,Windows 10。
请格外留意 Mysql 的版本,低于 Mysql 8 的 mybatis-config.xml 配置将与本文中的配置不同
文章目录
一. MyBatis 简介
- MyBatis 是支持定制化 SQL、存储过程、高级映射的优秀持久层框架
- MyBatis 避免了几乎所有的 JDBC 代码或手动设置参数以及获取结果集
- MyBatis 可以使用简单的 XML 或注释用于配置和原始映射,将接口和 Java 的 POJO(Plain Old Java Objects,即普通的 Java 对象)映射成数据库中的记录
- MyBatis 是一个半自动的 ORM (Object Relation Mapping)框架
二. 现有的持久化技术
- JDBC
- SQL 夹在 Java 代码里,耦合度高导致硬编码内伤
- 维护不易切实际开发需求中 SQL 有变化,修改频繁
- Hibernate 和 JPA
- 长难 SQL,对于 Hibernate 而言处理也不容易
- 内部自动生成 SQL,不容易做特殊优化
- 基于全映射的自动框架,大量字段的 POJO 进行部分映射比较困难。导致数据库性能下降
- MyBatis
- 对于开发人员而言,核心 SQL 依然需要自己优化
- SQL 和 Java 编码分开,功能边界清晰,一个专注业务,一个专注数据,更好的解耦合
三. MyBatis 项目搭建过程
-
添加 Maven 依赖(或者导入 jar 包)
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> <scope>compile</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.15</version> </dependency>
注意搭建 MyBatis 项目,需要另外添加 JDBC 依赖(或导入 JDBC 的 jar 包),本文中使用 Mysql 的 JDBC
-
创建 MyBatis 的核心(全局)配置文件 mybatis-config.xml
该配置文件在 Maven 项目中在 resource 目录下 配置以MySQL为数据库为例
<?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"> <!--配置数据库的驱动--> <!--注意,此处的配置只适用 Mysql 8及以上的版本--> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <!--配置数据库的URL--> <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatistest?useUnicode=true&characterEncoding=UTF-8&userSSL=false&serverTimezone=GMT%2B8"/> <!--配置数据库的登录用户名--> <property name="username" value="root"/> <!--配置数据库的登录用密码--> <property name="password" value="1244875112"/> </dataSource> </environment> </environments> <mappers> <!--设置映射文件,映射文件将在下面介绍--> <mapper resource="UserMapper.xml"/> <!--可以使用<package>标签引导映射到包目录下的Mapper文件,但要求为该包必须在全局配置文件同包目录下--> </mappers> </configuration>
-
创建映射文件 XxxMapper.xml,并配置
在 MySQL 数据库简单创建一个测试数据库:
User表:
uid userName password age sex 1 admin 123456 23 男 在 Maven 项目的 resources 目录下创建映射文件 UserMapper.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="org.example.Mapper.UserMapper"> <!--操作标签,uid为映射接口的抽象方法名,resultType为该抽象方法的返回值类型,需书写全类名--> <!--org.example.Bean.User 为测试的实体类,在下文中将列出--> <select id="getUserByUid" resultType="org.example.Bean.User"> <!--具体操作的SQL语句--> select * from User where uid = #id </select> </mapper>
-
创建 mapper 接口,实现两个绑定
UserMapper.xml 实现了两个绑定
- 接口全限定名要和映射文件的命名空间( 标签的 namespace 属性)保持一致
- 接口中的方法名和 SQL 语句的 id ( 标签的属性)保持一致,返回值与 resultType( 标签的属性) 一致
UserMapper.xml 中涉及到的类资源与映射接口如下
User.java 实体类
package org.example; public class User private Integer uid; private String userName; private String password; private Integer age; private String sex; public User() public User(String uid, String userName, String password, Integer age, String sex) this.uid = uid; this.userName =userName; this.password = password; this.age = age; this.sex = sex; public Integer getUid() return uid; public void setUid(Integer uid) this.uid = uid; 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 getSex() return sex; public void setSex(String sex) this.sex = sex; @Override public String toString() return "User" + "uid=" + uid + ", userName='" + userName + '\\'' + ", password='" + password + '\\'' + ", age=" + age + ", sex='" + sex + '\\'' + '';
UserMapper.java 映射接口
package org.example.Mapper; import org.example.Bean.User; public interface UserMapper User getUserByUid(int uid);
-
获取 MyBatis 操作数据库的会话对象 sqlSession 与测试
简单的测试当前的程序,过程中获取 sqlSession 对象
package org.example.Main; 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 org.example.Bean.User; import org.example.Mapper.UserMapper; import java.io.IOException; import java.io.InputStream; public class run public static void main(String[] args) throws IOException //将资源开启为 inputstream 对象,加载全局配置文件 InputStream input = Resources.getResourceAsStream("mybatis-config.xml"); //以全局配置文件作为参数,使用 SqlSessionFactoryBuilder 建造一个 SqlSessionFactory 对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(input); //以 SqlSessionFactory 文件创建一个 SqlSession 对象 //参数true表示事务将会自动提交 SqlSession sqlSession = sqlSessionFactory.openSession(true); //使用 Sqlsession 创建映射关系对象 //getMapper() 会通过动态代理动态生成UserMapper的代理实现类 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //调用映射关系对象的方法,进行查询 User user = userMapper.getUserByUid(1); System.out.println(user);
运行结果
Useruid=1, userName='admin', password='123456', age=23, sex='男'
查询成功
注意
UserMapper 是一个接口,显然是无法实例化的,此处的 userMapper 对象时一个实现了 UserMapper 的类的对象。而这个类的具体实现是由 MyBatis 完成的。
- 总结
-
项目文件梳理
上述案例中一共创建了四个文件:mybatis-config 核心配置文件、UserMapper 映射配置文件、UserMapper 映射接口、User 实体类。目前,他们之间的联系、关联如图所示。mybatis-config 文件还记录了数据库相关的信息。 -
MyBatis 实现的映射
文章在前介绍过 MyBatis —— 可以将接口和 Java 的 POJO(Plain Old Java Objects,即普通的 Java 对象)映射成数据库中的记录。本例中,MyBatis 就实现了这种映射。User 是做为 Entity 实体。UserMapper 映射接口做为 DAO。
四. mybatis-config.xml 文件配置操作
-
<properties>
标签的使用在
<configuration>
标签下书写<properties>
标签。指定 properties 配置。<configuration> <properties> <propertiy name = "jdbc.driver" value = "com.mysql.cj.jdbc.Driver"/> </properties> </configuration>
此时
<property>
标签的属性可修改<environments default="development"> <environment id="development"> <dataSource> ... <property name = "driver" value = "$jdbc.driver"> ... </dataSource> </environment> </environments>
<propertiy>
标签相当于定义了一个键值对,name 属性 jdbc.driver 为键,value 属性为值,在该定义后,可在<configuration>
标签下文中使用$jdbc.driver
通过键取得值。 -
<properties>
标签与 .properties 资源文件联用在项目的 resource 目录下创建 .properties 资源文件,并在全局配置文件中使用。
jdbc.properties
jdbc.driver = com.mysql.cj.jdbc.Driver jdbc.url = jdbc:mysql://127.0.0.1:3306/mybatistest?useUnicode=true&characterEncoding=UTF-8&userSSL=false&serverTimezone=GMT%2B8 jdbc.username = root jdbc.password = 123456
在全局配置文件中引入 properties 文件
<!-- <properties>标签属性有两种 resource:在类路径下访问资源文件 url:在网络路径或磁盘路径下访问资源文件 --> <properties resource = "jdbc.properties"></properties>
在引入外部资源文件后,在全局配置中 标签下可以进行修改为
<dataSource> <proprety name = "diver" value = "$jdbc.driver" /> <property name = "url" value = "$jdbc.driver"/> <property name = "username" value = "$jdbc.driver"/> <property name = "password" value = "$jdbc.driver"/> </dataSource>
此方法使用 .properties 文件更有利于解耦合与后续的项目修改。.properties 资源文件的可读性与易修改性比 .xml 文件强
-
<settings>
标签的使用在全局配置文件中使用
<setting>
标签能够实现一些功能例如:
<settings> <!--将数据库字段名的下划线转换为驼峰式命名法则--> <setting name = "mapUnderscoreCamelCase" value = "true"/> </settings>
因为数据库的字段命名尝用下划线分开单词,例如本例中使用 userName 为实体类,并且数据库中的字段名也为 userName,若不同,例如数据库字段为 user_name,则读取 userName 数据值将会为 null,产生错误的结果。 而该设置可以避免这一问题,将数据库的下划线字段名自动识别为驼峰式的命名,并读取数据。
本文仅介绍这一功能,其他功能可参见 MyBatis 文档
-
<typeAliases>
标签的使用为一个 Java 类设置一个更短的名称
-
默认的类别名设置
<typeAliases> <!--为类型设置别名,type值为java类型,默认别名就是类型,且不区分大小写--> <!--此时在 Mapper.xml 文件中可以用 user 或 User 取代全类名使用--> <typeAliase type = "org.example.bean.User"/> </typeAliases>
此时在映射文件中,如 UserMapper.xml 可以修改类名称为
<!--resultType 属性此时使用的就是定义的别名--> <select id="getUserByUid" resultType="user"> select * from User where uid = #id </select>
-
指定别名以设置别名
<!--与上述的默认类型别名不同,此处指定了别名为 u--> <typeAliases> <typeAliase type = "org.example.bean.User" alias = "u"/> </typeAliases>
此时在映射文件中,如 UserMapper.xml 可以修改类名称为
<!--使用自定义的别名 u 代替全类名--> <select id="getUserByUid" resultType="u"> select * from User where uid = #id </select>
-
<package>
标签包批量别名<typeAliases> <package name = "org.example.bean"/> </typeAliases>
在 org.example.bean 下的所有类全部设置为默认别名
-
五. 数据库的增、删、改、查、操作
对于数据库的增删改查操作需要书写映射接口,与 Mapper 映射文件。
映射接口
package org.example;
public interface UserMapper
//通过uid获取用户对象
User getUserByUid(int uid);
//增加用户
void addUser(User user);
//更新,修改用户
void updateUser(User user);
//删除用户
void deleteUser(int uid);
//获取用户数量
Integer getCount();
//获取全体用户对象
List<User> getAllUser();
//设置 map 的键,因为在查询时传出所有员工的信息,可以把员工信息作为值,但是必须设置键
@MapKey("uid")
Map<Integer, User> getAllUserMap();
//以 map 集合获取一个员工信息
@MapKey("uid")
Map<Integer, Object> getUserMapByUid(String uid);
- 返回值为 void 的方法也可以设置返回值为 Integer 或 Boolean,Integer 类型表示多少行受影响,Boolean 类型表示是否影响到行。
UserMapper.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="org.example.Mapper.UserMapper">
<select id="getUserByUid" resultType="User">
select * from User where uid = #id
</select>
<!--返回值为 void 的方法无需规定 resultType 属性-->
<insert id = "addUser">
insert into user value(null,#uid,#user_name,#password,#age,#sex)
</insert>
<!-- parameterTyper 属性为传入值的类型,也可以不写,Mybatis会进行类型推断-->
<update id = "updateUser" parameterType = "User">
update user set user_name = #user_name, age = #age, sex = #sex where uid = #uid
</update>
<delete id = "deleteUser">
delete from user where uid = #uid
</delete>
<!--返回值为 Integer 来或得结果-->
<select id = "getCount" resultType = "Integer">
select count(uid) from user
</select>
<!--返回值为 List<User> 但是只需要书写集合内的元素类型即可-->
<select id = "getAllUser" resultType = "User">
select * from user
</select>
<!--注意一下两条语句的 resultType 类型为 User 而不是 Map-->
<select id = "getAllUserMap" resultType = "User">
select * from user
</select>
<select id = "getUserMapByUid" resultType = "User">
select * from user where uid = #uid
</select>
</mapper>
执行测试
package org.example.Main;
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 org.example.Bean.User;
import org.example.Mapper.UserMapper;
import java.io.IOException;
import java.io.InputStream;
public class run
public static void main(String[] args) throws IOException
InputStream input = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(input);
//注意,与前一个案例不同,此处没有填入参数true。因此事务需要手动提交
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//添加用户的操作
userMapper.addUser(new User(2, "user", "1024", 20, "女"));
//更新用户操作
userMapper.updateUser(new User(1,"newName","000000",24,"男"));
//根据 uid 删除用户操作
userMapper.deleteUser(2)
//计数
System.out.println(userMapper.getCount());
//返回值为 List 的全体查询
List<User> allUserList = userMapper.getAllUser();
for(User user : AllUserList)
System.out.println(user);
//返回值为 Map 的全体查询
Map<Integer, User> allUserMap = userMapper.getAllUserMap();
User u1 = (User) map.get(1);
System.out.println(u);
//返回值为 Map 的按 uid 查询
Map<Integer, User> userMap = userMapper.getUserMapByUid("1");
User u2 = (User) map.get(1);
System.out.println(u);
//提交事务
sqlSession.conmmit();
注意
本例中对于 UserMapper.xml 中的 resultType 与 Mapper 接口中方法返回值并不完全一致。
UserMapper 接口中
getAllUser()
返回值为 List<User> 但 UserMapper.xml 中对应的语句 resultType 为 User.MyBatis 在处理 List 集合返回值时会进行自动类型转换,仅需指定集合的泛型类型即可。
UserMapper 接口中
getAllUserMap
和getUserMapByid
方法返回值均为 Map<Integer, User>,但在 UserMapper.xml 中对应的 resultType 为 UserMyBatis 在处理 Map 集合时也会进行自动类型转换,而键的值取决于 UserMapper 接口中对应方法的注解
@MapKey()
。本例中设计为@MapKey("uid")
,因此 Map 的键值类型为 uid以上是关于MyBatisJava 持久层框架入门与实践 | 学习笔记的主要内容,如果未能解决你的问题,请参考以下文章