在 使用 Mybatis 简化 JDBC 操作 中,简单描述了 Mybatis 的使用。这一篇主要记录下如何集成 Spring boot
Spring Boot 集成 Mybatis 简明过程
创建一个 Spring Initalizr 工程,依赖选择 web、MySQL、Mybatis
在application.properties填入以下内容
1 2 3 4
| spring.datasource.url=jdbc:mysql://127.0.0.1:3306/neu?characterEncoding=UTF-8&useSSL=false spring.datasource.username=root spring.datasource.password=YourPassword spring.datasource.driver-class-name=com.mysql.jdbc.Driver
|
- 创建pojo包,创建 Student 实体类,跟数据库对应
1 2 3 4 5 6 7 8
| public class Student { Integer id; String name; String major; Integer grade;
}
|
- 创建mapper包,创建StudentMapper接口
在SpringBootApplication类中,添加@MapperScan("io.jerrysheh.student.mapper")
注解,即可不用在 mapper 包下面的每一个接口都注解Mapper了。
1 2 3 4 5 6
| @Mapper public interface StudentMapper {
@Select("SELECT * FROM student") List<Student> findAll(); }
|
如果有多个参数,用 @Param
注解
1 2
| @Update("update user set password=#{password} WHERE id=#{id}") void updatePassword(@Param("password") String password, @Param("id") Integer id);
|
- 创建Controller包,创建StudentController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @RestController public class StudentController {
@Autowired StudentMapper studentMapper;
@GetMapping("/listStudent") public void listStudent(){ List<Student> studentList = studentMapper.findAll(); for (Student student: studentList) { System.out.println(student.getName()); } } }
|
这样,运行后访问 127.0.0.1:8080/listStudent
,可看到控制台输出数据库查到的所有 student 名字。
xml 方式
有时候为了将SQL和Java代码隔离 ,会将 SQL 抽到 xml 里面,配置方法如下:
在application.properties填入以下内容(重要!!!)
1 2 3
| mybatis.mapper-locations=classpath:mapper/*.xml mybatis.type-aliases-package=com.jerrysheh.fun.entity mybatis.configuration.map-underscore-to-camel-case=true
|
在 resources 目录下创建 mapper 文件夹,再创建 productmapper.xml 文件
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?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="com.jerrysheh.fun.mapper.ProductMapper">
<select id="selectAll" resultType="com.jerrysheh.fun.entity.Product"> SELECT * FROM fun_product; </select>
<insert id="addProduct" > insert into fun_product(product_name, product_price) values (#{productName}, #{productPrice}) </insert> </mapper>
|
注意:namespace一定要填写对应的 mapper 接口,不能只到 package
编写单元测试
1 2 3 4 5 6 7 8 9 10 11 12 13
| @SpringBootTest public class test {
@Autowired ProductMapper productMapper;
@Test public void test(){ List<Product> productList = productMapper.selectAll(); productList.forEach(System.out::println); }
}
|
以下为Mybatis知识点
井字符和美元符的区别
#相当于对数据加上双引号,$相当于直接显示数据
#方式能够很大程度防止sql注入。$方式无法防止Sql注入。
动态SQL
虽然我们使用了注解,但是还是在注解接口CategoryMapper中使用了原生 SQL 语句。
1 2
| @Insert(" insert into category_ ( name ) values (#{name}) ") public int add(Category category);
|
其实,我们可以提供一个类,专门用来生成SQL语句
CategoryDynaSqlProvider.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| package com.jerrysheh.mapper; import org.apache.ibatis.jdbc.SQL;
public class CategoryDynaSqlProvider { public String list() { return new SQL() .SELECT("*") .FROM("category_") .toString();
} public String get() { return new SQL() .SELECT("*") .FROM("category_") .WHERE("id=#{id}") .toString(); }
public String add(){ return new SQL() .INSERT_INTO("category_") .VALUES("name", "#{name}") .toString(); } public String update(){ return new SQL() .UPDATE("category_") .SET("name=#{name}") .WHERE("id=#{id}") .toString(); } public String delete(){ return new SQL() .DELETE_FROM("category_") .WHERE("id=#{id}") .toString(); } }
|
然后修改我们的CategoryMapper接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.jerrysheh.mapper;
import com.jerrysheh.pojo.Category; import org.apache.ibatis.annotations.*;
import java.util.List;
public interface CategoryMapper {
@InsertProvider(type=CategoryDynaSqlProvider.class,method="add") public int add(Category category);
@DeleteProvider(type=CategoryDynaSqlProvider.class,method="delete") public void delete(int id);
@SelectProvider(type=CategoryDynaSqlProvider.class,method="get") public Category get(int id);
@UpdateProvider(type=CategoryDynaSqlProvider.class,method="update") public int update(Category category);
@SelectProvider(type=CategoryDynaSqlProvider.class,method="list") public List<Category> list(); }
|
这样就可以动态生成SQL语句了
- 注解中的
type=
填入我们的动态生成SQL类CategoryDynaSqlProvider.class
method=
填入CategoryDynaSqlProvider类里的方法
@Results结果映射
如果 javabean 的属性字段 跟 数据库字段一一对应,名字保持一致,则直接可以:
1 2
| @Select("select *from Demo where id=#{id}") public Demo selectById(int id);
|
但如果不对应,就要用@Result
修饰返回的结果集,而@Results
注解将指定的数据库列与指定JavaBean属性映射起来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Select("SELECT * FROM `wx_message_config` WHERE `content_key_words` IS NOT NULL AND LENGTH(content_key_words) > 0") @Results({ @Result(property = "msgType", column = "msg_type"), @Result(property = "eventType", column = "event_type"), @Result(property = "eventKey",column = "event_key"), @Result(property = "contentKeyWords",column = "content_key_words") }) List<WxMessageConfig> queryAllKeyWords();
@Select("SELECT * FROM `wx_message_config` WHERE `id` = #{id}") @Results({ @Result(property = "msgType", column = "msg_type"), @Result(property = "eventType", column = "event_type"), @Result(property = "eventKey",column = "event_key"), @Result(property = "contentKeyWords",column = "content_key_words") }) WxMessageConfig queryKwById(int id);
|
这样会导致写很多重复内容,可以用 @ResultMap(“id”)
1 2 3 4 5 6 7 8 9
| @Select("SELECT id, name, password FROM user WHERE id = #{id}") @Results(id = "userMap", value = { @Result(column = "id", property = "id", javaType = Integer.class), @Result(column = "name", property = "name", javaType = String.class), @Result(column = "password", property = "password", javaType = String.class) }) User findById(Integer id);
@Select("SELECT * FROM user") @ResultMap("userMap") List<User> fingAll();
|
一对多查询
假设有一张 商品表 和 一张 图片表, 一个商品对应多张图片
那么如何取出一个商品,包含商品的所有属性,以及对应的所有图片呢?
实体类
商品的所有字段,同时,要添加一个 List<String>
表示多张图片的集合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class Product { private Integer id; private Integer user_id; private String name; private String price; private Date gmt_create; private String description; private Integer cate_id; private Integer number;
private List<String> link;
}
|
图片的所有属性,用 String 表示图片地址
1 2 3 4 5
| public class Image { private Integer id; private Integer product_id; private String link; }
|
Mapper接口
在图片的Mapper接口中,根据商品id找到对应的所有图片
1 2 3
| @Select("SELECT link from image WHERE product_id = #{product_id}") List<String> getImageLinksByProductId(Integer product_id);
|
在商品的Mapper接口中,通过 @Results
和 @Many
来进行关联
1 2 3 4 5 6 7 8 9 10
| @Select("select * from product WHERE number > 0 ORDER BY id DESC") @Results({ // 这里要对id进行限定,否则 id 会为 null @Result(property = "id", column = "id"),
// 将 image 的 link 和 product 的 id 绑定,通过 @Many 查询 返回 List @Result(property = "link", column = "id", javaType = List.class, many = @Many(select = "com.zsc.tradeplatform.mapper.ImageMapper.getImageLinksByProductId")), }) List<Product> getAll();
|
控制器
1 2 3 4 5
| @ResponseBody @GetMapping("/api/product") public List<Product> getAllProduct(){ return productService.getAllProduct(); }
|
访问 127.0.0.1:8080/api/product
查看结果