作者:追夢1819
原文:https://www.cnblogs.com/yanfei1819/p/10876339.html
版權宣告:本文為博主原創文章,轉載請附上博文連結!
引言
在以往的專案中,對於dao層的常規 CRUD 操作,我們通常使用 JPA、JDBC 時會做一個所謂的BaseDaoMapper 以減少程式碼量。而通用 Mapper 剛好是這一環節的替代品,程式碼更簡單,更優雅,也是 Mybatis 用的很廣泛的一個外掛。
不過需要注意的一點是,通用 Mapper 支援單標操作,不支援通用的多表聯合查詢。
使用
下面通過用增刪改查的簡單示例,演示 Mapper 的用法,本系列的demo都是按照 Java web 的專案架構來,所以還是按照 MVC的模式進行。不過注意,因為此處只是為了演示最基本的功能。為了防止捨本逐末,故程式碼作了最簡單的優化,只保留最基本的功能程式碼,實際業務程式碼可能會複雜得多。
準備工作,初始化資料庫:
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`age` int(3) NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 50 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (14, 'admin', 21);
INSERT INTO `user` VALUES (48, 'teacher', 20);
INSERT INTO `user` VALUES (49, 'student', 22);
SET FOREIGN_KEY_CHECKS = 1;
建立 SpringBoot 專案。
首先,引入maven依賴(因為通用 Mapper 是建立在 Mybatis 的基礎上的,所以在引入 Mapper 之前,必須先引入Mybatis 依賴):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
然後,配置資料庫資訊:
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.1.88:3306/test?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=pass123
下一步,建立實體類以作資料庫對映:
package com.yanfei1819.mybatismapperdemo.entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* Created by 追夢1819 on 2019-05-07.
*/
@Table(name = "user")
public class User {
@Id
@GeneratedValue(generator = "JDBC") // 自增欄位
private Long id;
private String name;
private int age;
// set/get 省略
}
上述的註解:
@Table(name = "user")
對映資料表名@Id
主鍵id@GeneratedValue(generator = "JDBC")
自增欄位這會令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法來取出由資料庫內部生成的主鍵(比如:像 MySQL 和 SQL Server 這樣的關聯式資料庫管理系統的自動遞增欄位)。 這種情況對應的xml類似下面這樣:
<insert id="insertAuthor" useGeneratedKeys="true" keyProperty="id"> insert into Author (username,password,email,bio) values (#{username},#{password},#{email},#{bio}) </insert>
如果表欄位與實體類屬性不一致,可以用註解
再下一步,建立代理介面:
package com.yanfei1819.mybatismapperdemo.dao;
import com.yanfei1819.mybatismapperdemo.entity.User;
import tk.mybatis.mapper.common.Mapper;
/**
* Created by 追夢1819 on 2019-05-07.
*/
@org.apache.ibatis.annotations.Mapper
public interface UserMapper extends Mapper<User> {
}
該介面就是通用 Mapper 的核心部分。該介面繼承 Mapper。
再者,建立service層介面和實現類:
package com.yanfei1819.mybatismapperdemo.service;
import com.yanfei1819.mybatismapperdemo.entity.User;
import java.util.List;
/**
* Created by 追夢1819 on 2019-05-07.
*/
public interface UserService {
int insertUser(User user);
int updateUser(User user);
int deleteUser(Long id);
List<User> listUsers();
User getUserById(Long id);
}
實現類:
package com.yanfei1819.mybatismapperdemo.service.impl;
import com.yanfei1819.mybatismapperdemo.dao.UserMapper;
import com.yanfei1819.mybatismapperdemo.entity.User;
import com.yanfei1819.mybatismapperdemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* Created by 追夢1819 on 2019-05-07.
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public int insertUser(User user) {
return userMapper.insert(user);
}
@Override
public int updateUser(User user) {
return userMapper.updateByPrimaryKey(user);
}
@Override
public int deleteUser(Long id) {
return userMapper.deleteByPrimaryKey(id);
}
@Override
public List<User> listUsers() {
return userMapper.selectAll();
}
@Override
public User getUserById(Long id) {
return userMapper.selectByPrimaryKey(id);
}
}
最後,建立controller層:
package com.yanfei1819.mybatismapperdemo.web.controller;
import com.yanfei1819.mybatismapperdemo.entity.User;
import com.yanfei1819.mybatismapperdemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* Created by 追夢1819 on 2019-05-07.
*/
@RestController
public class UserController {
@Autowired
private UserService service;
@GetMapping("/listUsers")
public List<User> listUser(){
return service.listUsers();
}
@GetMapping("/getUserById/{id}")
public User getUserById(@PathVariable Long id){
return service.getUserById(id);
}
@PostMapping("/insertUser")
public int insertUser(User user){
return service.insertUser(user);
}
@PostMapping("/updateUser")
public int updateUser(User user){
return service.updateUser(user);
}
@GetMapping("/deleteUser/{id}")
public int deleteUser(@PathVariable Long id){
return service.deleteUser(id);
}
}
啟動類是:
package com.yanfei1819.mybatismapperdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//import tk.mybatis.spring.annotation.MapperScan; // 注意此處引入的jar
@SpringBootApplication
//@MapperScan("com.yanfei1819.mybatismapperdemo.db")
public class MybatisMapperDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisMapperDemoApplication.class, args);
}
}
要注意一點, UserMapper 介面中的 @org.apache.ibatis.annotations.Mapper
註解可以被啟動類中的註解 @MapperScan(value = {"com.yanfei1819.mybatismapperdemo.db.*"})
代替。
但是這裡要注意一個坑,使用了通用 Mapper 的匯入的 @MapperScan
的jar包,不再是 import org.mybatis.spring.annotation.MapperScan;
,而是 import tk.mybatis.spring.annotation.MapperScan;
,不然會報錯。
啟動專案,可測試結果。
常用API
此處列舉一些常用的API:
增
int insert(T record);
儲存一個實體,null的屬性也會儲存,不會使用資料庫預設值int insertSelective(T record);
儲存一個實體,null的屬性不會儲存,會使用資料庫預設值查
List<T> selectAll();
查詢全部結果T selectByPrimaryKey(Object key);
根據主鍵欄位進行查詢,方法引數必須包含完整的主鍵屬性,查詢條件使用等號List<T> selectByExample(Object example);
根據Example條件進行查詢List<T> select(T record);
根據實體中的屬性值進行查詢,查詢條件使用等號T selectOne(T record);
根據實體中的屬性進行查詢,只能有一個返回值,有多個結果是丟擲異常,查詢條件使用等號int selectCount(T record);
根據實體中的屬性查詢總數,查詢條件使用等號改
int updateByPrimaryKey(T record);
根據主鍵更新實體全部欄位,null值會被更新int updateByExample(@Param("record") T record, @Param("example") Object example);
根據Example條件更新實體record
包含的全部屬性,null值會被更新int updateByPrimaryKeySelective(T record);
根據主鍵更新屬性不為null的值刪
int deleteByPrimaryKey(Object key);
根據主鍵欄位進行刪除,方法引數必須包含完整的主鍵屬性int delete(T record);
根據實體屬性作為條件進行刪除,查詢條件使用等號int deleteByExample(Object example);
根據Example條件刪除資料
參考
文件一:https://mapperhelper.github.io/docs
文件二:https://github.com/abel533/Mapper
總結
專案中常規的增刪改查是避免不了的,而且邏輯幾乎不變。如果每一個增刪改查都寫一個方法,那冗餘程式碼想必不少。即使是程式碼生成器生成程式碼【參考本人部落格:SpringBoot第八篇:整合 MyBatis-Generator】,也是不利於程式碼的擴充的。
針對這個問題,有很多解決方案,甚至自己封裝一個通用方法,也未嘗不可(本人工作初期,專案中所用的基本都是這種解決方案)。不過在多方案中,個人還是比較喜歡通用 Mapper,一是它與 MyBatis 無縫對接;二是程式碼量極少,無需配置;當然,更重要的是,已經有現成的輪子了,何必再重複去造輪子呢?