概述
上一篇讲到了JPA,使用JPA进行单表操作还是十分方便的,但是多表操作的时候还是有些力不从心,简单点说就是很麻烦。所以我们就需要用到一个新的工具——Mybatis,今天我们就来讲讲使用Mybatis操作数据库,当然,还是单表,先学会了走再学跑。
工程结构
Mybatis
MyBatis是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
Mybatis可以高度定制SQL语句,但它不仅仅只是写一堆SQL代码,它使用XML文件来控制与数据库交互的内容,在XML里面可以定义各种参数和返回的结果集,并且支持动态SQL。
POM
说那么多越说越懵,还是看看怎么用吧。首先是依赖,Mybatis提供了对Spring Boot的支持,在Spring Boot中使用Mybatis只需要引入一个mybatis-spring-boot-starter的依赖就可以了。但是今天加入的不止是这一个依赖,druid-spring-boot-starter依赖也就是druid是阿里开源的一个数据库连接池,代替了自带的hikari连接池,连接池就是控制数据库连接的一个工具;lombok是一个对pojo类自动生成构造方法和setter和getter的一个工具,有了它就可以简化pojo类了。
<?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>com.imsoulcoder</groupId>
<artifactId>springboot_mybatis</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<dependencies>
<!--导入lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--导入MariaDB连接驱动-->
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
</dependency>
<!--导入Druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.17</version>
</dependency>
<!--导入Mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--测试依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
application.yml
这次的application.yml配置文件比较上次的只是有一些小小的改动。首先是连接池的改动,指明了type为Druid的数据源,以及后面Druid验证语句的一个配置,这个配置是根据数据库类型(MariaDB或者Oracle再或者MSSQL之类的)来指明的。还有就是Mabatis的配置,就是注明了需要加载的mapper配置文件(mapper是实现Mybatis的一个称呼,分为接口和配置文件也就是实现接口的xml)的位置,以及pojo类位置,和命名规则。
server:
port: 8082 # 启动使用的端口号
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 指明数据源类型为Druid
driver-class-name: org.mariadb.jdbc.Driver # 数据库连接驱动类名
url: jdbc:mariadb://localhost:3306/jx?characterEncoding=utf-8 # 数据库连接url
username: root # 数据库用户名
password: toor # 数据库密码
druid: # 连接池
validation-query: SELECT 1
mybatis:
mapper-locations: classpath:/mapper/*.xml # 需要加载的mapper配置文件的位置,当前表示在resources目录下的mapper文件家下的所有xml文件
type-aliases-package: com.imsoulcoder.pojo # 存放pojo类的包
configuration:
map-underscore-to-camel-case: true # 下划线命名转换成驼峰命名
POJO类
还是先说说我们的泡jio类,这次的pojo类和上次比较有些不同。第一是因为我们没有使用JPA,所以上次用的注解全都不需要了;第二是因为这次引入了lombok依赖,所以省略了Getter和Setter,增加了lombok的注解,三个注解代表自动生成的各种方法。使用Mybatis没有增加注解。
package com.imsoulcoder.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
// 全参数构造方法 User(int id, String name, String pwd)
@AllArgsConstructor
// 无参数构造方法 User()
@NoArgsConstructor
// Getter、Setter、equals、canEqual、hashCode、toString
@Data
public class User {
private int id;
private String name;
private String pwd;
}
Mapper接口
Mapper接口为其它层提供了操作数据库的各种方法,它只是一个接口,我们不用写实现它的Java代码,但是之后要写XML配置文件。
package com.imsoulcoder.mapper;
import com.imsoulcoder.pojo.User;
import java.util.List;
public interface UserMapper {
//根据主键(id)删除
int deleteByPrimaryKey(Integer id);
//插入
int insert(User record);
//根据主键(id)查询
User selectByPrimaryKey(Integer id);
//查询全部
List<User> selectAll();
//根据用户的id属性修改
int updateByPrimaryKey(User record);
}
入口类
为什么把入口类提到前面来说呢?因为这次的入口类需要加入一条MapperScan注解来指明Mapper接口的位置,也就是存放Mapper接口的包,这样才能扫描到接口。
package com.imsoulcoder;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.imsoulcoder.mapper")
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
Mapper.xml
刚才写的Mapper接口没有Java代码实现,那它怎么用呢?Mybatis会把Mapper.xml解析成需要的Mapper接口的实现,所以我们需要写一个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">
<!--namespace对应Mapper接口-->
<mapper namespace="com.imsoulcoder.mapper.UserMapper">
<!--定义基础结果集,用于返回结果,type为需要返回的结果集的类型-->
<resultMap id="BaseResultMap" type="com.imsoulcoder.pojo.User">
<!--id代表数据库中的主键id,jdbcType和Java类型有一个固定的对应关系,column代表数据库中字段,property代表pojo类中的属性-->
<id column="id" jdbcType="INTEGER" property="id"/>
<!--result表示除id外的结果-->
<result column="name" jdbcType="VARCHAR" property="name"/>
<result column="pwd" jdbcType="VARCHAR" property="pwd"/>
</resultMap>
<!--delete表示这个标签的作用是用来删除,id为Mapper接口中对应的方法,parameterType表示参数类型,#{id,jdbcType=INTEGER}这里的id为传入的参数-->
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
delete
from user
where id = #{id,jdbcType=INTEGER}
</delete>
<!--insert表示这个标签用来插入,参数为实体对象的时候取用的时候可以直接取用属性-->
<insert id="insert" parameterType="com.imsoulcoder.pojo.User">
insert into user (id, name, pwd)
values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{pwd,jdbcType=VARCHAR})
</insert>
<!--update表示这个标签用来修改-->
<update id="updateByPrimaryKey" parameterType="com.imsoulcoder.pojo.User">
update user
set name = #{name,jdbcType=VARCHAR},
pwd = #{pwd,jdbcType=VARCHAR}
where id = #{id,jdbcType=INTEGER}
</update>
<!--select表示这个标签用来查询,resultMap为返回的结果集的id,就是最上面定义的那个,当然也可以定义其它结果集-->
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select id, name, pwd
from user
where id = #{id,jdbcType=INTEGER}
</select>
<select id="selectAll" resultMap="BaseResultMap">
select id, name, pwd
from user
</select>
</mapper>
这个XML文件大概就是这么写,存放的位置要在application.yml标注的地方,不然有可能识别不到,代码中的jdbcType和Java类型的对应关系大概如下
JDBC Type Java Type
CHAR String
VARCHAR String
LONGVARCHAR String
NUMERIC java.math.BigDecimal
DECIMAL java.math.BigDecimal
BIT boolean
BOOLEAN boolean
TINYINT byte
SMALLINT short
INTEGER INTEGER
BIGINT long
REAL float
FLOAT double
DOUBLE double
BINARY byte[]
VARBINARY byte[]
LONGVARBINARY byte[]
DATE java.sql.Date
TIME java.sql.Time
TIMESTAMP java.sql.Timestamp
CLOB Clob
BLOB Blob
ARRAY Array
DISTINCT mapping of underlying type
STRUCT Struct
REF Ref
DATALINK java.net.URL[color=red][/color]
Service层
接口
package com.imsoulcoder.service;
import com.imsoulcoder.pojo.User;
import java.util.List;
public interface UserService {
int deleteByPrimaryKey(Integer id);
int insert(User record);
User selectByPrimaryKey(Integer id);
List<User> selectAll();
int updateByPrimaryKey(User record);
}
实现类
package com.imsoulcoder.service.impl;
import com.imsoulcoder.mapper.UserMapper;
import com.imsoulcoder.pojo.User;
import com.imsoulcoder.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service("userService")
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
public int deleteByPrimaryKey(Integer id) {
return userMapper.deleteByPrimaryKey(id);
}
public int insert(User record) {
return userMapper.insert(record);
}
public User selectByPrimaryKey(Integer id) {
return userMapper.selectByPrimaryKey(id);
}
public List<User> selectAll() {
return userMapper.selectAll();
}
public int updateByPrimaryKey(User record) {
return userMapper.updateByPrimaryKey(record);
}
}
在实现类中可以加入代码的业务逻辑,只是为了实现数据库操作功能的话偷懒就不加了。需要说明的是Service注解,该注解表明这是一个Service层的实现,括号里面的值对应自动装载(Autowired)时的变量名。
Test
package com.imsoulcoder.test;
import com.imsoulcoder.pojo.User;
import com.imsoulcoder.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserTest {
@Autowired
private UserService userService;
@Test
public void testDeleteByPrimaryKey() {
System.out.println("删除前:" + userService.selectAll());
for (int i = 2; i < 10; i += 2) {
userService.deleteByPrimaryKey(i);
}
System.out.println("删除后:" + userService.selectAll());
}
@Test
public void testInsert() {
System.out.println("插入前:" + userService.selectAll());
for (int i = 1; i < 10; i++) {
User user = new User();
user.setName("JX" + i);
user.setPwd("123");
userService.insert(user);
}
System.out.println("插入后:" + userService.selectAll());
}
@Test
public void testSelectByPrimaryKey() {
System.out.println("查询单个:" + userService.selectByPrimaryKey(2));
}
@Test
public void testSelectAll() {
System.out.println("查询全部:" + userService.selectAll());
}
@Test
public void testUpdateByPrimaryKey() {
User user = userService.selectByPrimaryKey(5);
System.out.println("修改前:" + user);
user.setPwd("1q2w3e4r5t6y");
userService.updateByPrimaryKey(user);
System.out.println("修改后:" + userService.selectByPrimaryKey(5));
}
}