Mybatis 在當下互聯網開發環境,十分重要。本章主要講述 Mybatis 如何使用。
從本系列開始,都需要用到 mysql 數據庫 和其他一些參考的數據庫。請准備相關環節。本章需要以下環境支撐:
- mysql 5.6+
- jdk1.8+
- spring boot 2.1.6
- idea 2018.1
1 准備數據庫
數據庫教程系列都是使用相同的數據,如在 Spring Boot JDBC 使用教程使用的一樣
字段 | 類型 | 主鍵 | 說明 |
---|---|---|---|
id | int | 是 | 自動編號 |
user_name | varchar(100) | 否 | 用戶名 |
password | varchar(255) | 否 | 密碼 |
last_login_time | date | 否 | 最近登錄時間 |
sex | tinyint | 否 | 性別 0男 1女 2其他 |
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_name` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`last_login_time` datetime DEFAULT NULL,
`sex` tinyint(4) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=armscii8;
-- ----------------------------
-- Records of t_user
-- ----------------------------
BEGIN;
INSERT INTO `t_user` VALUES (1, 'json', '123', '2019-07-27 16:01:21', 1);
INSERT INTO `t_user` VALUES (2, 'jack jo', '123', '2019-07-24 16:01:37', 1);
INSERT INTO `t_user` VALUES (3, 'manistal', '123', '2019-07-24 16:01:37', 1);
INSERT INTO `t_user` VALUES (4, 'landengdeng', '123', '2019-07-24 16:01:37', 1);
INSERT INTO `t_user` VALUES (5, 'max', '123', '2019-07-24 16:01:37', 1);
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
2 新建 Spring Boot 工程項目
- File > New > Project,如下圖選擇
Spring Initializr
然后點擊 【Next】下一步 - 填寫
GroupId
(包名)、Artifact
(項目名) 即可。點擊 下一步
groupId=com.fishpro
artifactId=mybatis - 選擇依賴
Spring Web Starter
前面打鈎,勾選SQL選項的 mybatis , mysql。 - 項目名設置為
spring-boot-study-mybatis
.
3 依賴引入 Pom.xml 配置
在新建工程的時候,如果選擇 Mybatis
依賴,則不需要單獨配置,以下是本項目的全部依賴。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
3 Mybatis 的工程配置 application.yml
無論是 jdbc
還是 mybatis
都需要對 數據源進行配置,而且配置項是一樣的。除了數據源基礎的配置,我們還需要配置 mybatis
的映射文件 *.xml 的路徑,mybatis
的獨立 config.xml
文件路徑等。
mapper-locations
配置實體與數據庫表的映射文件xml位置,我們配置為/src/main/resource/mybatis/**maper.xml
下map-underscore-to-camel-case
開啟mybatis的駝峰命名轉換type-aliases-package
指定 實體domain
的類,這是com.fishpro
下所有以domain
結尾的實體類。
server:
port: 8086
mybatis:
configuration:
map-underscore-to-camel-case: true
mapper-locations: mybatis/**/*Mapper.xml
type-aliases-package: com.fishpro.**.domain
針對 mybatis 的配置,我們也可以把所有 mybatis 配置配置到單獨的 config 文件中。
5 編寫示例代碼
這里我們首次使用到 三層結構來演示本項目,即 controller-service-dao-mapper-mybatis
本示例包括新增的頁面
- src/main/java/com/fishpro/mybatis/controller/UserController.java 控制層 rest api
- src/main/java/com/fishpro/mybatis/domain/UserDO.java 實體對象
- src/main/java/com/fishpro/mybatis/dao/UserDao.java Dao數據庫訪問層
- src/main/java/com/fishpro/mybatis/service/UserService.java 服務層包括了接口+接口實現
- src/main/java/com/fishpro/mybatis/service/impl/UserServiceImpl.java 服務層包括了接口+接口實現
- src/main/resources/mybatis/UserMapper.xml 映射 xml 文件
5.1 映射文件 UserMapper.xml
UserMapper.xml 是一個以 mybatis 語法來編寫的 xml 映射文件。
+ mapper 節點是根節點 具有屬性 namespace 表示 mapper 對應的 java 的 Dao 接口類
|--select 查詢節點
|--where
|--choose
|--when
|--otherwise
|--insert 插入節點
|--update 更新節點
|--delete 刪除節點
詳細的代碼如下
<?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.fishpro.mybatis.dao.UserDao">
<select id="get" resultType="com.fishpro.mybatis.domain.UserDO">
select `id`,`user_name`,`password`,`last_login_time`,`sex` from t_user where id = #{value}
</select>
<select id="list" resultType="com.fishpro.mybatis.domain.UserDO">
select `id`,`user_name`,`password`,`last_login_time`,`sex` from t_user
<where>
<if test="id != null and id != '-1' " > and id = #{id} </if>
<if test="userName != null and userName != '' " > and user_name = #{userName} </if>
<if test="password != null and password != '' " > and password = #{password} </if>
<if test="lastLoginTime != null and lastLoginTime != '' " > and last_login_time = #{lastLoginTime} </if>
<if test="sex != null and sex != '-1' " > and sex = #{sex} </if>
</where>
<choose>
<when test="sort != null and sort.trim() != ''">
order by ${sort} ${order}
</when>
<otherwise>
order by id desc
</otherwise>
</choose>
<if test="offset != null and limit != null">
limit #{offset}, #{limit}
</if>
</select>
<select id="count" resultType="int">
select count(*) from t_user
<where>
<if test="id != null and id != '-1' " > and id = #{id} </if>
<if test="userName != null and userName != '' " > and user_name = #{userName} </if>
<if test="password != null and password != '' " > and password = #{password} </if>
<if test="lastLoginTime != null and lastLoginTime != '' " > and last_login_time = #{lastLoginTime} </if>
<if test="sex != null and sex != '-1' " > and sex = #{sex} </if>
</where>
</select>
<insert id="save" parameterType="com.fishpro.mybatis.domain.UserDO" useGeneratedKeys="true" keyProperty="id">
insert into t_user
(
`user_name`,
`password`,
`last_login_time`,
`sex`
)
values
(
#{userName},
#{password},
#{lastLoginTime},
#{sex}
)
</insert>
<update id="update" parameterType="com.fishpro.mybatis.domain.UserDO">
update t_user
<set>
<if test="userName != null">`user_name` = #{userName}, </if>
<if test="password != null">`password` = #{password}, </if>
<if test="lastLoginTime != null">`last_login_time` = #{lastLoginTime}, </if>
<if test="sex != null">`sex` = #{sex}</if>
</set>
where id = #{id}
</update>
<delete id="remove">
delete from t_user where id = #{value}
</delete>
<delete id="batchRemove">
delete from t_user where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>
5.2 實體對象 UserDO
與數據庫表對應的(可自定義)對象實體類
public class UserDO {
private Integer id;
private String userName;
private String password;
private Integer sex;
private Date lastLoginTime;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
public Date getLastLoginTime() {
return lastLoginTime;
}
public void setLastLoginTime(Date lastLoginTime) {
this.lastLoginTime = lastLoginTime;
}
}
5.3 數據庫訪問層 UserDao
Dao 是一個接口層,接口方法對應 mybatis/**Mapper.xml 中 Mapper 節點下的 id 值。例如上面的 <select id="get" resultType="com.fishpro.mybatis.domain.UserDO">
那么對應的接口方法 UserDO get(Integer id)
Dao 必須使用 @Mappger注解,才能實現從Dao到Mapper.xml的映射
/**
* 數據庫訪問層 用戶Dao t_user
* @author fishpro
*/
@Mapper
public interface UserDao {
/**
* 對應節點 select id="get" resultType="com.fishpro.mybatis.domain.UserDO"
* */
UserDO get(Integer id);
/**
* 對應節點 select id="list" resultType="com.fishpro.mybatis.domain.UserDO"
* */
List<UserDO> list(Map<String, Object> map);
/**
* 對應節點 select id="count" resultType="int"
* */
int count(Map<String, Object> map);
/**
* 對應節點 insert id="save" parameterType="com.fishpro.mybatis.domain.UserDO" useGeneratedKeys="true" keyProperty="id"
* */
int save(UserDO user);
/**
* 對應節點 update id="update" parameterType="com.fishpro.mybatis.domain.UserDO"
* */
int update(UserDO user);
/**
* 對應節點 delete id="remove"
* */
int remove(Integer id);
/**
* 對應節點 delete id="batchRemove"
* */
int batchRemove(Integer[] ids);
}
5.4 服務類 UseService
注意 UserServiceImpl 一定要使用 @Service 注解,才能實現 UserService類自動注入功能
在本示例中只是簡單的增刪改查功能
UserService 接口類
public interface UserService {
UserDO get(Integer id);
List<UserDO> list(Map<String, Object> map);
int count(Map<String, Object> map);
int save(UserDO user);
int update(UserDO user);
int remove(Integer id);
int batchRemove(Integer[] ids);
}
UserServiceImpl 實現類
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public UserDO get(Integer id){
return userDao.get(id);
}
@Override
public List<UserDO> list(Map<String, Object> map){
return userDao.list(map);
}
@Override
public int count(Map<String, Object> map){
return userDao.count(map);
}
@Override
public int save(UserDO user){
return userDao.save(user);
}
@Override
public int update(UserDO user){
return userDao.update(user);
}
@Override
public int remove(Integer id){
return userDao.remove(id);
}
@Override
public int batchRemove(Integer[] ids){
return userDao.batchRemove(ids);
}
}
5.5 控制層實現 Rest Api 增刪改查接口 UserController
本示例代碼使用標准的 Restful 風格編寫 具體代碼如下:
/**
* RESTful API + Mybatis 風格示例 對資源 user 進行操作
* 本示例沒有使用數據庫,也沒有使用 service 類來輔助完成,所有操作在本類中完成
* 請注意幾天
* 1.RESTful 風格使用 HttpStatus 狀態返回 GET PUT PATCH DELETE 通常返回 201 Create ,DELETE 還有時候返回 204 No Content
* 2.使用 RESTful 一定是要求具有冪等性,GET PUT PATCH DELETE 本身具有冪等性,但 POST 不具備,無論規則如何定義冪等性,需要根據業務來設計冪等性
* 3.RESTful 不是神丹妙葯,實際應根據實際情況來設計接口
* */
@RestController
@RequestMapping("/api/user")
public class UserController {
@Autowired
private UserService userService;
/**
* 測試用 參數為 name
* */
@RequestMapping("/hello")
public String hello(String name){
return "Hello "+name;
}
/**
* SELECT 查詢操作,返回一個JSON數組
* 具有冪等性
* */
@GetMapping("/users")
@ResponseStatus(HttpStatus.OK)
public Object getUsers(){
return userService.list(new HashMap<>());
}
/**
* SELECT 查詢操作,返回一個新建的JSON對象
* 具有冪等性
* */
@GetMapping("/users/{id}")
@ResponseStatus(HttpStatus.OK)
public Object getUser(@PathVariable("id") String id){
if(null==id){
return null;
}
return userService.get(Integer.valueOf(id));
}
/**
* 新增一個用戶對象
* 非冪等
* 返回 201 HttpStatus.CREATED 對創建新資源的 POST 操作進行響應。應該帶着指向新資源地址的 Location 頭
* */
@PostMapping("/users")
@ResponseStatus(HttpStatus.CREATED)
public Object addUser(@RequestBody UserDO user){
if(user.getId()==0){
return null;
}
userService.save(user);
return user;
}
/**
* 編輯一個用戶對象
* 冪等性
* */
@PutMapping("/users/{id}")
@ResponseStatus(HttpStatus.CREATED)
public Object editUser(@PathVariable("id") String id, @RequestBody UserDO user){
userService.update(user);
return user;
}
/**
* 刪除一個用戶對象
* 冪等性
* 返回 HttpStatus.NO_CONTENT 表示無返回內容
* */
@DeleteMapping("/users/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteUser(@PathVariable("id") String id){
userService.remove(Integer.valueOf(id));
}
}
6 運行示例
右鍵 MybatisApplication
> Run MybatisApplication
在瀏覽器輸入 http://localhost:8086/api/user/users
使用 PostMan 測試工具可測試 GET\POST\PUT\DELETE 動作的 Restful api
7 問題思考
- 如何自動生成代碼
- 如何動態配置數據源
- 如何分表分庫
- xml的詳細語法由哪些坑
- xml 好還是 注解好
- 如何解決事物處理
- 擴庫事物如何處理
下一章節我們演示下使用 注解來實現