SpringBoot 2.1.5.RELEASE
java version 1.8.0_231
mysql 5.7
一、工程添加数据库驱动和Mybatis依赖
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<!--当前工程的pom继承了springboot的父pom,所以mysql驱动的版本号是继承父pom中mysql的版本号,在这里可以不写版本-->
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
二、配置文件写入数据源信息
- 在application.yml中配置数据源信息,并使用hikri作为数据连接池
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/dream_hammer_mall?characterEncoding=UTF-8&useSSL=false&useUnicode=true&serverTimezone=UTC
username: root
password: #你的数据库密码
hikari:
connection-timeout: 30000 # 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 默认:30秒
minimum-idle: 5 #最小连接数
maximum-pool-size: 20 #最大连接数
auto-commit: true #事务自动提交
idle-timeout: 600000 #连接超时的最大时长(毫秒),超时则被释放(retired)
pool-name: DataSourceHikariCP #连接池名称
max-lifetime: 1800000 #连接生命时长,空闲未被使用超过最大时长则被释放
connection-test-query: select 1
三、mybatis使用准备工作
- 创建数据库表(这里使用演示表Student)
演示表名为student,有三个字段:id(主键),name(姓名),age(年龄)
CREATE TABLE
student
(
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(16),
age INT,
PRIMARY KEY (id)
)
ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_general_ci;
- 编写实体类Student
public class Student {
private Integer id;
private String name;
private Integer age;
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return Objects.equals(id, student.id) &&
Objects.equals(name, student.name) &&
Objects.equals(age, student.age);
}
@Override
public int hashCode() {
return Objects.hash(id, name, age);
}
}
- 开启MapperScan注解
在SpringBoot的启动类上添加 org.mybatis.spring.annotation.MapperScan 这个注解
@SpringBootApplication
//MapperScan注解,开启Mapper扫描,扫描site.teamo.mall.dao包下所有mapper类
@MapperScan(basePackages = {"site.teamo.mall.dao"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
四、Mybatis常用使用方式
1.全注解方式
注解的方式可以完成基本的crud操作:@Insert,@Select,@Update,@Delete
优点:对于简单表和简单的sql业务使用起来比较方便,不需要去创建xml,修改配置文件等
缺点:复杂业务,使用这种方式,会使得代码看起来比较乱,而且这种方式,相当于将sql硬编码在代码中,如需对sql进行修改,需重新编译代码
@Component
@Mapper
public interface StudentDao1 {
@Select("select * from student where id = #{id}")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "name", column = "name"),
@Result(property = "age", column = "age")
})
Student selectOne(@Param("id") String studentId);
/**
* 当你的方法参数名和Sql参数名相同时,可以不使用@Param注解,
* eg:
*
* @Select("select * from student where id = #{id}")
* Student selectOne(String studentId);
*/
@Insert("insert into student (id,name,age) values(#{id},#{name},#{age})")
Integer insertOne(Student student);
@Update("update student set name=#{name}, age=#{age} where id = #{id}")
Integer updateOne(Student student);
@Delete("delete from student where id = #{id}")
Integer deleteOne(String id);
}
2.Provider注解+Java代码方式
这种方式是结合注解和Java代码的方式,使用@InsertProvider,@SelectProvider,@UpdateProvider,@DeleteProvider注解在方法上,在使用Java代码来拼装sql
优点:可以使用Java代码来编写多种判断逻辑,在Sql拼接的过程中可以根据数据进行多种操作,比如数据校验,数据格式转换,数据个性化设置(默认值)等
缺点:sql完全由代码拼接比较散乱,不便于管理,虽然可以根据数据进行多种校验操作,但是在设计上并不推荐把数据的业务逻辑放在拼装sql这一块,会使得代码比较杂乱
- StudentDao代码
@Component
@Mapper
public interface StudentDao2 {
@SelectProvider(type = StudentDao2Provider.class, method = "selectOne")
Student selectOne(String studentId);
@InsertProvider(type = StudentDao2Provider.class,method = "insertOne")
Integer insertOne(Student student);
@UpdateProvider(type = StudentDao2Provider.class,method = "updateOne")
Integer updateOne(Student student);
@DeleteProvider(type = StudentDao2Provider.class,method = "deleteOne")
Integer deleteOne(String id);
}
- Provider代码
public class StudentDao2Provider {
public String selectOne(String id) {
String sql = new SQL() {{
SELECT("id,name,age");
FROM("student");
WHERE("id = #{id}");
}}.toString();
return sql;
}
public String insertOne(Student student) {
String sql = new SQL() {{
INSERT_INTO("student");
if (student == null) {
throw new RuntimeException("插入数据不能为空");
}
VALUES("id","#{id}");
VALUES("name", "#{name}");
//添加逻辑判断,如果age不合法,就设置默认15岁
if (student.getAge() == null || student.getAge() > 100 || student.getAge() < 0) {
VALUES("age","15");
}else {
VALUES("age", "#{age}");
}
}}.toString();
return sql;
}
public String updateOne(Student student) {
String sql = new SQL() {{
UPDATE("student");
if (student == null) {
throw new RuntimeException("更新数据不能为空");
}
if (student.getName() != null) {
SET("name=#{name}");
}
if (student.getAge() == null || student.getAge() > 100 || student.getAge() < 0) {
throw new RuntimeException("学生年龄不能小于0大于100");
}
SET("age=#{age}");
WHERE("id=#{id}");
}}.toString();
return sql;
}
public String deleteOne(String id) {
String sql = new SQL() {{
DELETE_FROM("student");
WHERE("id=#{id}");
}}.toString();
return sql;
}
}
3.xml方式
只需要定义接口,sql的编写和实体类的映射都在xml中配置
优点:sql自由度很高,都放在xml里便于统一管理和优化,同时代码比较简洁
缺点:简单的查询也需要修改xml,手写sql比较繁琐,同时由于sql自由度变高了,对sql了解不多的开发人员使用起来稍显困难
- StudentDao代码
@Mapper
@Component
public interface StudentDao3 {
Student selectOne(String studentId);
Integer insertOne(Student student);
Integer updateOne(Student student);
Integer deleteOne(String id);
}
- StudentDao.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="site.teamo.mall.dao.StudentDao3">
<resultMap id="base_result_map" type="site.teamo.mall.bean.Student">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="age" property="age"/>
</resultMap>
<select id="selectOne" resultMap="base_result_map" parameterType="java.lang.String">
select * from student where id = #{id}
</select>
<insert id="insertOne" parameterType="site.teamo.mall.bean.Student">
insert into student(id,name,age) values (#{id},#{name},#{age})
</insert>
<update id="updateOne" parameterType="site.teamo.mall.bean.Student">
update student set name = #{name},age = #{age} where id = #{id}
</update>
<delete id="deleteOne" parameterType="java.lang.String">
delete from student where id = #{id}
</delete>
</mapper>
4.通用Mapper方式(xml+example)
java代码结合xml,简单的crud直接代码调用通用方法,复杂的业务sql使用xml便于管理和优化
优点:这种方式弥补了上述几种方式的不足,即实现了基本crud的通用方法,在简单查询时可以直接使用,也使用了xml配置可以统一管理,优化复杂sql,总体上是最推荐的一种mybatis使用方式
缺点:需要去实体类添加实体与数据库字段映射关系的注解
使用方式稍有不同,步骤如下
- 在原有的基础上添加新pom依赖
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.1.5</version>
</dependency>
- SpringBoot启动类上MapperScan进行更换,注释掉org下MapperScan换用tk包下的MapperScan
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//import org.mybatis.spring.annotation.MapperScan;
import tk.mybatis.spring.annotation.MapperScan;
@SpringBootApplication
@MapperScan(basePackages = {"site.teamo.mall.dao"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
- 在实体类上加上与数据资源映射的注解
public class Student {
//使用通用Mapper时需要添加这些注解
@Id
private Integer id;
@Column(name = "name")
private String name;
@Column(name = "age")
private Integer age;
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return Objects.equals(id, student.id) &&
Objects.equals(name, student.name) &&
Objects.equals(age, student.age);
}
@Override
public int hashCode() {
return Objects.hash(id, name, age);
}
}
- StudentDao代码
@Component
public interface StudentDao4 extends Mapper<Student>, MySqlMapper<Student> {
/**
* 通用Mapper中有很多基础的crud方法,基本查询就可以使用通用Mapper中的方法
* 当你有复杂的逻辑业务sql时,也可以自定义方法,如下就是自定义了一个演示方法
*/
Student mySelectOne(String id);
}
- StudentDao.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="site.teamo.mall.dao.StudentDao4">
<resultMap id="base_result_map" type="site.teamo.mall.bean.Student">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="age" property="age"/>
</resultMap>
<select id="mySelectOne" parameterType="java.lang.String" resultMap="base_result_map">
select * from student where id =#{id}
</select>
</mapper>
最后附上我的测试类
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import site.teamo.mall.bean.Student;
import site.teamo.mall.dao.StudentDao1;
import site.teamo.mall.dao.StudentDao2;
import site.teamo.mall.dao.StudentDao3;
import site.teamo.mall.dao.StudentDao4;
@RunWith(SpringRunner.class)
@SpringBootTest
@EnableAutoConfiguration
@MapperScan(basePackages = {"site.teamo.mall.dao"})
public class MybatisTest {
@Autowired
private StudentDao1 studentDao1;
@Autowired
private StudentDao2 studentDao2;
@Autowired
private StudentDao3 studentDao3;
@Autowired
private StudentDao4 studentDao4;
@Test
public void test1(){
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(20);
Assert.assertEquals(1L,studentDao1.insertOne(student)*1L);
Assert.assertEquals(student,studentDao1.selectOne("1"));
student.setName("李四");
Assert.assertEquals(1L,studentDao1.updateOne(student)*1L);
Assert.assertEquals(student,studentDao1.selectOne("1"));
Assert.assertEquals(1L,studentDao1.deleteOne("1")*1L);
}
@Test
public void test2(){
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(20);
Assert.assertEquals(1L,studentDao2.insertOne(student)*1L);
Assert.assertEquals(student,studentDao2.selectOne("1"));
student.setName("李四");
Assert.assertEquals(1L,studentDao2.updateOne(student)*1L);
Assert.assertEquals(student,studentDao2.selectOne("1"));
Assert.assertEquals(1L,studentDao2.deleteOne("1")*1L);
}
@Test
public void test3(){
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(20);
Assert.assertEquals(1L,studentDao3.insertOne(student)*1L);
Assert.assertEquals(student,studentDao3.selectOne("1"));
student.setName("李四");
Assert.assertEquals(1L,studentDao3.updateOne(student)*1L);
Assert.assertEquals(student,studentDao3.selectOne("1"));
Assert.assertEquals(1L,studentDao3.deleteOne("1")*1L);
}
@Test
public void test4(){
Student student = new Student();
student.setId(1);
student.setName("张三");
student.setAge(20);
Assert.assertEquals(1L,studentDao4.insert(student)*1L);
Assert.assertEquals(student,studentDao4.selectByPrimaryKey("1"));
student.setName("李四");
Assert.assertEquals(1L,studentDao4.updateByPrimaryKey(student)*1L);
Assert.assertEquals(student,studentDao4.mySelectOne("1"));
Assert.assertEquals(1L,studentDao4.deleteByPrimaryKey(1)*1L);
}
}
五、总结
-
hikriCP是SpringBoot的默认数据连接池,在日常工程中使用比较多的还有druid,druid是由阿里巴巴开源的一款数据连接池,两个数据连接池都比较优秀
-
mybatis的四种使用方式各有优缺点使用场景也不同
全注解方式,适合快速演示,或者简单表测试时使用,只要工程中有引入mybatis依赖既可以直接在代码中写sql使用
Provider注解加Java代码的方式,适合对sql不是很了解的开发人员使用,或者时sql的生成跟业务数据关联性比较强的时候使用
接口加xml方式,适用于对sql比较了解,以及项目中sql全都需要严格管理的项目使用
通用mapper方式,这个是比较推荐的,项目中简单sql不强制统一管理的时候可以使用,对于复杂sql也可以进行管理
大家在使用的时候根据自己的需要选择就可以了,如果你觉得这些都不好,那么你也可以自己设计实现一个自己ORM框架
关注公众号【爱做梦的锤子】后台回复【java知识点】可下载我整理的完整版思维导图
文章欢迎转载,转载请注明出处,个人公众号【爱做梦的锤子】,全网同id,个站 http://te-amo.site,欢迎关注,里面会分享更多有用知识,还有我的私密照片
网友评论