源码精品专栏
原创 | Java 2019 超神之路,很肝~
中文详细注释的开源项目
RPC 框架 Dubbo 源码解析
网络应用框架 Netty 源码解析
消息中间件 RocketMQ 源码解析
数据库中间件 Sharding-JDBC 和 MyCAT 源码解析
作业调度中间件 Elastic-Job 源码解析
分布式事务中间件 TCC-Transaction 源码解析
Eureka 和 Hystrix 源码解析
Java 并发源码
摘要: 原创出处 http://www.iocoder.cn/Spring-Boot/MyBatis/ 「芋道源码」欢迎转载,保留摘要,谢谢!
1. 概述
2. MyBatis + XML
2.1 引入依赖
2.2 Application
2.3 应用配置文件
2.4 MyBatis 配置文件
2.5 UserDO
2.6 UserMapper
2.7 简单测试
3. MyBatis + 注解
3.1 差异部分
3.2 UserMapper
3.3 简单测试
4. MyBatis-Plus
4.1 引入依赖
4.2 Application
4.3 应用配置文件
4.4 UserDO
4.5 UserMapper
4.6 简单测试
5. tkmybatis
5.1 引入依赖
5.2 Application
5.3 应用配置文件
5.4 MyBatis 配置文件
5.5 UserDO
5.6 UserMapper
5.7 简单测试
666. 彩蛋
本文,我们基于 Spring Boot 2.X 版本。
在 DAL 数据访问层,目前会有三种方向的解决方案:
JDBC
MyBatis
JPA
艿艿自己在 知识星球 中,做过一个简单的调研,看看大家使用哪个为主。结果是 MyBatis > JPA > JDBC 。这个也符合在知乎上看到的两篇文章:
《MyBatis 为什么在国内相当流行?》
《为什么阿里巴巴的持久层采用 iBatis 框架,而不使用 hibernate 框架呢?感觉 hibernate 更厉害的样子?》
而每个团队使用 MyBatis 方式还有不同,主要是如下:
注意,几种方式可以组合使用。
MyBatis + XML
MyBatis + 注解
MyBatis-Plus
tkmybatis
艿艿的团队,最终我们使用 XML 的方式,因为 XML 便于可以看到每个表使用到的 SQL ,方便做优化和管理。
后来,考虑到提高开发效率,很多标准的数据库的 CRUD 操作,编写还是比较枯燥乏味浪费时间,所以使用 MyBatis-Plus 简化。当然,一些相对复杂的 SQL ,还是会考虑使用 XML 。
下面,我们上面列的四种方式,逐个来入门。
示例代码对应仓库:mybatis-xml 。
本小节,我们会使用 mybatis-spring-boot-starter
自动化配置 MyBatis 主要配置。同时,在 XML 中编写相应的 SQL 操作。
在 pom.xml
文件中,引入相关依赖。
org.springframework.boot
spring-boot-starter-parent
2.1.3.RELEASE
4.0.0
lab-12-mybatis
org.springframework.boot
spring-boot-starter-jdbc
mysql
mysql-connector-java
5.1.48
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.1.1
org.springframework.boot
spring-boot-starter-test
test
具体每个依赖的作用,胖友自己认真看下艿艿添加的所有注释噢。
创建 Application.java
类,配置 @MapperScan
注解,扫描对应 Mapper 接口所在的包路径。代码如下:
// Application.java
@SpringBootApplication
@MapperScan(basePackages = "cn.iocoder.springboot.lab12.mybatis.mapper")
public class Application {
}
`cn.iocoder.springboot.lab12.mybatis.mapper` 包路径下,就是我们 Mapper 接口所在的包路径。
建议 1 :因为这里是做示例。实际项目中,可以考虑创建一个 MyBatisConfig 配置类,将 @MapperScan
注解添加到其上。
在 resources
目录下,创建 application.yaml
配置文件。配置如下:
spring:
# datasource 数据源配置内容
datasource:
url: jdbc:mysql://47.112.193.81:3306/testb5f4?useSSL=false&useUnicode=true&characterEncoding=UTF-8
driver-class-name: com.mysql.jdbc.Driver
username: testb5f4
password: F4df4db0ed86@11
# mybatis 配置内容
mybatis:
config-location: classpath:mybatis-config.xml # 配置 MyBatis 配置文件路径
mapper-locations: classpath:mapper/*.xml # 配置 Mapper XML 地址
type-aliases-package: cn.iocoder.springboot.lab12.mybatis.dataobject # 配置数据库实体包路径
具体的每个配置项,胖友自己认真看下艿艿添加的所有注释噢。
在 resources
目录下,创建 mybatis-config.xml
配置文件。配置如下:
因为在数据库中的表的字段,我们是使用下划线风格,而数据库实体的字段使用驼峰风格,所以通过 mapUnderscoreToCamelCase = true
来自动转换。
在 cn.iocoder.springboot.lab12.mybatis.dataobject
包路径下,创建 UserDO.java 类,用户 DO 。代码如下:
// UserDO.java
public class UserDO {
/**
* 用户编号
*/
private Integer id;
/**
* 账号
*/
private String username;
/**
* 密码(明文)
*
* ps:生产环境下,千万不要明文噢
*/
private String password;
/**
* 创建时间
*/
private Date createTime;
// ... 省略 setting/getting 方法
}
对应的创建表的 SQL 如下:
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户编号',
`username` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '账号',
`password` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '密码',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
在 cn.iocoder.springboot.lab12.mybatis.mapper
包路径下,创建 UserMapper 接口。代码如下:
// UserMapper.java
@Repository
public interface UserMapper {
int insert(UserDO user);
int updateById(UserDO user);
int deleteById(@Param("id") Integer id); // 生产请使用标记删除,除非有点想不开,嘿嘿。
UserDO selectById(@Param("id") Integer id);
UserDO selectByUsername(@Param("username") String username);
List selectByIds(@Param("ids")Collection ids);
}
@Repository
注解,用于标记是数据访问 Bean 对象。在 MyBatis 的接口,实际非必须,只是为了避免在 Service 中,@Autowired
注入时无需报警。
@Param
注解,声明变量名。
在方法为单参数时,非必须。
在方法为多参数时,必须。艿艿自己的编程习惯,禁止使用 Map 作为查询参数,因为无法通过方法的定义,很直观的看懂具体的用途。
细心的胖友,肯定会发现例如说 #selectByUsername(@Param("username") String username)
等方法,是使用 By 字段结尾,这是为什么呢?一般情况下,在 SQL 中的 WHERE
条件字段,我们建议能够带在方法名后。原因无它,简单明了。如果是多个字段,可以使用 AND 分隔。当然,如果查询字段比较多,可能方法名会比较长。
在 resources/mapper
路径下,创建 UserMapper.xml
配置文件。代码如下:
id, username, password, create_time
INSERT INTO users (
username, password, create_time
) VALUES (
#{username}, #{password}, #{createTime}
)
UPDATE users
, username = #{username}
, password = #{password}
WHERE id = #{id}
DELETE FROM users
WHERE id = #{id}
建议 1 :对于绝大多数查询,我们是返回统一字段,所以可以使用 标签,定义 SQL 段。对于性能或者查询字段比较大的查询,按需要的字段查询。
建议 2 :对于数据库的关键字,使用大写。例如说,SELECT
、WHERE
等等。
建议 3 :基本是每“块”数据库关键字占用一行,胖友可以看看艿艿写的每一行示例。一定要排版干净,毕竟我们是有代码洁癖的男孩子。
创建 UserMapperTest 测试类,我们来测试一下简单的 UserMapper 的每个操作。代码如下:
// UserMapperTest.java
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void testInsert() {
UserDO user = new UserDO().setUsername(UUID.randomUUID().toString())
.setPassword("nicai").setCreateTime(new Date());
userMapper.insert(user);
}
@Test
public void testUpdateById() {
UserDO updateUser = new UserDO().setId(1)
.setPassword("wobucai");
userMapper.updateById(updateUser);
}
@Test
public void testDeleteById() {
userMapper.deleteById(2);
}
@Test
public void testSelectById() {
userMapper.selectById(1);
}
@Test
public void testSelectByUsername() {
userMapper.selectByUsername("yunai");
}
@Test
public void testSelectByIds() {
List users = userMapper.selectByIds(Arrays.asList(1, 3));
System.out.println("users:" + users.size());
}
}
具体的,胖友可以自己跑跑,妥妥的。
如果胖友嫌弃手写 MyBatis XML 很麻烦,可以看看 IDEA MyBatisCodeHelper-Pro 插件。在没有使用 MyBatis-Plus 插件之前,使用过蛮长一段时间,我以前的老大也在用。
当然,也可以考虑使用 MyBatis Generator (MBG) 。