Spring(二) SpringBoot 集成 Mybatis
1300字约4分钟
JavaWebSQL
2018-04-17

在 使用 Mybatis 简化 JDBC 操作 中,简单描述了 Mybatis 的使用。这一篇主要记录下如何集成 Spring boot
Spring Boot 集成 Mybatis 简明过程
创建一个 Spring Initalizr 工程,依赖选择 web、MySQL、Mybatis
在application.properties填入以下内容
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 实体类,跟数据库对应
 
public class Student {
    Integer id;
    String name;
    String major;
    Integer grade;
    // 省略 getter setter
}- 创建mapper包,创建StudentMapper接口
 
在SpringBootApplication类中,添加
@MapperScan("io.jerrysheh.student.mapper")注解,即可不用在 mapper 包下面的每一个接口都注解Mapper了。
@Mapper
public interface StudentMapper {
    @Select("SELECT * FROM student")
    List<Student> findAll();
}如果有多个参数,用 @Param 注解
@Update("update user set password=#{password} WHERE id=#{id}")
void updatePassword(@Param("password") String password, @Param("id") Integer id);- 创建Controller包,创建StudentController
 
@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填入以下内容(重要!!!)
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 文件
<?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
编写单元测试
@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 语句。
@Insert(" insert into category_ ( name ) values (#{name}) ")
public int add(Category category);其实,我们可以提供一个类,专门用来生成SQL语句
CategoryDynaSqlProvider.java
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接口
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 的属性字段 跟 数据库字段一一对应,名字保持一致,则直接可以:
@Select("select *from Demo where id=#{id}")  
public Demo selectById(int id);但如果不对应,就要用@Result修饰返回的结果集,而@Results注解将指定的数据库列与指定JavaBean属性映射起来。
@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”) 
@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> 表示多张图片的集合
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;
    // 省略 getter setter
}图片的所有属性,用 String 表示图片地址
public class Image {
    private Integer id;
    private Integer product_id;
    private String link;
}Mapper接口
在图片的Mapper接口中,根据商品id找到对应的所有图片
// 根据商品id找图片
@Select("SELECT link from image WHERE product_id = #{product_id}")
List<String> getImageLinksByProductId(Integer product_id);在商品的Mapper接口中,通过 @Results 和 @Many 来进行关联
// 取出在售的所有商品,最新的排前面
@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();控制器
@ResponseBody
@GetMapping("/api/product")
    public List<Product> getAllProduct(){
        return productService.getAllProduct();
    }访问 127.0.0.1:8080/api/product 查看结果

