这里介绍如何使用Mybatis操作数据库。
因为Mybatis最好还是和Spring框架结合来使用,作为Spring的持久层来完成数据库操作,所以这里首先介绍一下Springboot的基本层次。
Springboot(或者说是SpringMVC)相当于使用了实体层、持久层和业务层三层来完成数据库操作。控制层相当于普通JAVA程序的main或者实现某种特定功能的函数。
1.导入Maven
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.7.2version>
<relativePath/>
parent>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.2.2version>
dependency>
dependencies>
和两个依赖;意味着本项目不能使用它所代表的类,只能使用它所依赖的类,也就是中的类;表明本项目既可以使用它所代表的类,也可以使用它所依赖的类;2.项目文件目录结构

xxx.xxx.xxx格式,而不要直接在java文件夹下创建类;util包用来写自定义的功能性组件;SpringbootMain类,配置文件是application.yml;resources下的mapper是用来保存真正的数据库映射xml文件的,每个xml和持久层的xxxMapper类一一对应。server:
port: 8081
mybatis:
type-aliases-package: cn.jeremy.xxx.entity
mapper-locations: classpath:mapper/*.xml
configuration:
map-underscore-to-camel-case: false
spring:
datasource:
url: jdbc:sqlserver://xxx:1433;DatabaseName=xxx;encrypt=true;trustServerCertificate=true
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
username: xxx
password: xxx
application.yml中进行Springboot、database和mybatis的配置;application.yml而用application.properties来配置,但yml写起来更省事一点,两者其实也很容易相互转换;type-aliases-package配置是要写上所有需要使用Mybaitis管理的实体类(也就是数据表对应的对象)所在包,多个包可用逗号分隔;mapper-locations用来写xxxMapper.xml的路径,classpath就是指resources文件夹下的根路径;map-underscore-to-camel-case用来进行数据库表属性和实体类的成员变量之间的自动映射,如果关闭了需要手动进行映射;8080端口,这会和Zookeeper默认端口以及其他的Web应用冲突,所以最好是换一个端口,如8081。前面已经提到了,Mybatis是Springboot的持久层框架,所以Springboot的持久层这里是采用Mybatis来实现(虽然持久层也可以用别的框架来实现,不局限于Mybatis)。整个Springboot框架的完整示例可以参考:Spring Boot 集成 MyBatis和 SQL Server实践和IDEA创建Spring Boot项目,这里重点描述持久层的Mybatis实现。持久层的Mybatis实现需要同时完成接口和xml两个部分。
1.Dao/Mapper包中的接口实现:
package cn.jeremy.xxx.dao;
import cn.jeremy.xxx.entity.Report;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface ReportMapper {
public List<Report> selectAll();
public Report selectOne(@Param("uid")String uid);
public int updateStatus(@Param("uid")String uid, @Param("status") int status);
public int updateUpdateAt(@Param("uid")String uid, @Param("current") String current);
}
@Mapper注解;xml文件中实现,再由Mybatis代为管理,自动注入到类对象中;@Param用来映射Java函数参数与xml参数之间的对应关系;2.xml文件中的映射实现
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.jeremy.xxx.dao.ReportMapper">
<resultMap id="resultMap" type="cn.jeremy.pdf_extractor.entity.Report">
<id property="uid" javaType="java.lang.String" column="uuid" jdbcType="CHAR">id>
<result property="name" javaType="java.lang.String" column="name" jdbcType="CHAR">result>
<result property="status" javaType="java.lang.Integer" column="status" jdbcType="INTEGER">result>
<result property="updateAt" javaType="java.sql.Timestamp" column="lastupdate_at" jdbcType="TIMESTAMP">result>
resultMap>
<sql id="Base_Column_List">
uuid, status, lastupdate_at
sql>
<select id="selectAll" resultMap="resultMap">
select * from xxx
select>
<select id="selectOne" resultMap="resultMap">
select <include refid="Base_Column_List"/> from xxx
where uuid = #{uid, jdbcType=CHAR}
select>
<update id="updateStatus">
update xxx
set status = #{status, jdbcType=INTEGER}
where uuid = #{uid, jdbcType=CHAR}
update>
<update id="updateUpdateAt">
update xxx
set update_at = '#{current, jdbcType=TIMESTAMP}'
where uuid = #{uid, jdbcType=CHAR}
update>
mapper>
namespace表明了该xml文件是和哪个持久层接口对应;resultMap是映射java变量和数据库表属性的关键,它给出了实体层类变量和属性之间的一一对应关系,可以定义了之后在下面的增删查改标签中直接引用;和标签映射一种数据库操作,它们的id绑定的是接口的成员函数;resultType也是映射变量类型和数据库属性类型的一种方式,它直接表明对应的实体层类名,resultType和resultMap只能同时使用一个,可以参考博文:resultMap和resultType区别详解;resultMap而用resultType,Mybatis会自动在函数返回值类型和数据库查询结果建立映射,依据是数据库属性名称和实体层类变量名称之间的关系。要使用自动映射,首先要在application.yml中将map-underscore-to-camel-case设置为true,其次是所有的Java变量名称为小驼峰命名,数据库属性名称为下划线命名,且除命名方法不同外它们之间字母需要完全相同;resultMap中没写映射关系或者写错,又或者自动映射命名之间没有完全对应),则Java变量会赋初始默认值;标签相当于定义了一个变量,可以插入在下方的增删查改SQL语句中,减少重复;补充:
insert的操作参考下面:<insert id="createMessage" parameterType="cn.jeremy.xxx.entity.Message">
insert into <include refid="Table"/>(<include refid="Base_Column_List"/>)
values(#{message.uid, jdbcType=CHAR}, #{message.reportUid, jdbcType=CHAR},
#{message.createAt, jdbcType=TIMESTAMP}, #{message.code, jdbcType=INTEGER},
#{message.jsonData, jdbcType=VARCHAR})
insert>
xxx.xxx的形式来对应调用;parameterType,不推荐用parameterMap(已被官方丢弃,也很难找到可参考的案例了);resultMap,不推荐用resultType(虽然能自动映射,但要求bean的命名和数据表命名完全对应,弹性空间小);在封装好业务层之后,便可以在Springboot框架中使用Mybatis操作数据库了。使用的场景可以分成两类:
1.在Controller中使用
@RestController表明当前类是Controller;@Autowired引入业务层接口,Mybatis会在使用时自动注入类对象;@RestController
public class ReportController {
@Autowired
private ReportService reportService;
@RequestMapping(value = "/getAllReports", method = RequestMethod.GET)
public List<Report> getAllReports() {
return reportService.getAllReports();
}
}
2.不在Controller中使用
除了在controller使用,有时也需要在自己编写的工具类,也就是util包中的类中调用数据库,但由于这些类没有使用Controller注解,所以是没有办法直接让Mybatis注入Service层接口的。可以采用下面的方式:
@Component让Springboot知道这个是需要自动注入的类;init()函数中指向本对象实例;@PostConstruct函数修饰init()函数,让它在对象生成之后被自动调用,完成依赖注入;package cn.jeremy.xxx.util;
import cn.jeremy.xxx.service.ReportService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class Consumer implements Runnable {
@Autowired
private ReportService reportService; // Service层接口
public static Consumer staticConsumer;
@PostConstruct
public void init() {
staticConsumer = this; // 用一个静态对象指向当前实例
}
public Consumer() {
}
@Override
public void run(){
System.out.println("Consumer thread is running.");
// 更新数据库:status = 101
staticConsumer.reportService.updateStatus(uid, 101); // 用静态对象调用Service层接口
}
}
有些功能或者执行需要在Springboot启动之后就执行,或者需要贯穿整个程序的生命周期(例如某些监听的行为),这时候需要实现Springboot的初始化操作。方法这里介绍以下两种:
1.ApplicationRunner接口的用法
ApplicationRunner接口;package cn.jeremy.xxx;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootMain implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
// 创建动态配置
String[] sourceArgs = args.getSourceArgs();
for(String a: sourceArgs) {
System.out.println(a);
}
// 下方可以编写Springboot的初始化操作
}
public static void main(String[] args) {
SpringApplication.run(SpringbootMain.class, args);
}
}
2.@PostConstruct注解的用法
@PostConstruct修饰的函数中实现;最终发布的时候是需要把项目打包部署的,主要参考博客:maven–使用Idea打包SpringBoot项目–方法/实例。
pom.xml中添加构建项:<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
标签项和同级;java -jar xxx.jar 参数1 参数2 ...参数n
<dependency>
<groupId>com.github.bingoohuanggroupId>
<artifactId>idworker-clientartifactId>
<version>0.0.8version>
dependency>
import org.n3r.idworker.Sid;
this.uid = Sid.next();