MyBatis
可以簡單的使用註解或XML 的方式進行配置和對映,通過將引數對映到配置的SQL 形成最終執行的SQL 語法,最後將SQL 語法執行結果對映成Java 物件返回。
在開始實作功能以前,我們會先簡單介紹一下ORM 以及它的優缺點,再來展示如何實作註解及XML 兩種使用方式,而實作的功能與上一篇Day 11 - Spring Boot & JdbcTemplate一樣。
ORM,全名為Object Relational Mapping,中文名稱為物件關係對映,目的是為了解決面向物件與關聯式資料庫中資料類型互不匹配的問題,它的作法是在實體物件和關聯式資料庫之間做一個映射,這樣在操作實體物件時就不需要使用複雜的SQL 語法,只需要操作物件的屬性和方法。
解決操作資料庫的重複性
我們對資料庫的操作無非就是增、刪、改、查四種操作,但當我們在實作持久層時,我們還是需要寫大量的程式碼,只因為我們操作的資料表不同,而使用ORM 則可以自動生成CRUD 語法,開發時就可以把更多的精力放在業務邏輯上。
增加應用程式的擴展性和靈活性並防止SQL 注入
當我們在編寫持久層邏輯時,如果操作的是MySQL 資料庫時,我們就會使用相應的語法以及配置,但當我們需要更換資料庫時,整個持久層的邏輯就需要重新編寫。
而ORM 做到了實體物件與資料庫之間的映射,ORM 可以通過映射關係自動生成SQL 語法,因此不必再編寫重複的程式碼且不用擔心SQL 注入的問題。
@Insert
: 用於新增敘述。@Select
: 用於查詢敘述。@Update
: 用於修改敘述。@Delete
: 用於刪除敘述。@Mapper
public class DemoUserMapper {
@Insert("INSERT INTO user(name, age) VALUES(#{name}, #{age})")
public int add(User user);
@Select("SELECT * FROM user")
public List<User> getList();
@Select("SELECT * FROM user WHERE id = #{id}")
public User getDataById(String id);
@Update("UPDATE user SET name = #{name}, age = #{age} WHERE id = #{id}")
public int updateDataById(User user);
@Delete("DELETE FROM user Where id = #{id}")
public int deleteDataById(String id);
}
@Results
: 用於多個欄位的對映關係。@Result
: 用於單一欄位的對映關係。@ResultMap
: 根據ID 連結XML 的。@Results({
@Result(property = "username", column = "USERNAME"),
@Result(property = "password", column = "PASSWORD"),
})
@Selete("SELECT * FROM user")
public List<User> getList();
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
package com.example.demo.mapper;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import com.example.demo.entity.MemberAccount;
@Mapper
public interface MemberAccountMapper {
@Insert(" INSERT INTO test_project.member_account ( "
+ " USERNAME, PASSWORD, SALT, "
+ " CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME "
+ " ) "
+ " VALUE ( "
+ " #{username}, #{password}, #{salt}, "
+ " #{create_by}, NOW(), #{update_by}, NOW() "
+ " ) ")
public Integer insert(MemberAccount memberAccount);
@Select(" SELECT "
+ " ID, USERNAME, PASSWORD, SALT "
+ " FROM "
+ " test_project.member_account "
+ " WHERE "
+ " USERNAME = #{username} ")
public MemberAccount findMemberAccountByUsername(String username);
@Update(" UPDATE "
+ " test_project.member_account "
+ " SET "
+ " PASSWORD = #{password}, UPDATE_BY = #{update_by}, UPDATE_TIME = NOW() "
+ " WHERE "
+ " ID = #{id} ")
public Integer update(MemberAccount memberAccount);
}
package com.example.demo.mapper;
import java.util.UUID;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.example.demo.entity.MemberAccount;
@SpringBootTest
public class MemberAccountMapperTest {
@Autowired
private MemberAccountMapper memberAccountMapper;
@Test
public void insert() {
MemberAccount memberAccount = new MemberAccount();
memberAccount.setUsername("username@email.com");
memberAccount.setPassword("password");
String salt = UUID.randomUUID().toString().toUpperCase().replaceAll("-", "");
memberAccount.setSalt(salt);
memberAccount.setCreate_by(memberAccount.getUsername());
memberAccount.setUpdate_by(memberAccount.getUsername());
Integer id = memberAccountMapper.insert(memberAccount);
System.out.println(id);
}
@Test
public void findMemberAccountByUsername() {
String username = "username@email.com";
MemberAccount memberAccount = memberAccountMapper.findMemberAccountByUsername(username);
if(memberAccount != null) System.out.println(memberAccount.toString());
}
@Test
public void update() {
MemberAccount memberAccount = new MemberAccount();
memberAccount.setId("1");
memberAccount.setPassword("123456");
memberAccount.setUpdate_by("username@email.com");
Integer result = memberAccountMapper.update(memberAccount);
System.out.println(result);
}
}
mybatis.mapper-locations=classpath:mappers/*.xml
package com.example.demo.mapper;
import com.example.demo.entity.MemberAccount;
public interface MemberAccountMapper {
public Integer insert(MemberAccount memberAccount);
public MemberAccount findMemberAccountByUsername(String username);
public Integer update(MemberAccount memberAccount);
}
在上一個步驟定義持久層接口時並沒有定義@Service
或是@Repository
之類的註解,為了讓持久層能夠被Spring 管理,推薦使用@MapperScan(...)
指定掃描路徑,雖然也可以在Mapper 上使用@Mapper
註解,但指定掃描路徑就不用每個Mapper 都下註解。
package com.example.demo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.demo.mapper")
public class SpringBootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApplication.class, args);
}
}
<?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">
<!-- namespace 對應持久層的介面 -->
<mapper namespace="com.example.demo.mapper.MemberAccountMapper" > <!-- id 對應持久層介面的方法,parameterType 為引數資料型別,resultType 為返回資料型別 -->
<insert id="insert" parameterType="com.example.demo.entity.MemberAccount">
INSERT INTO test_project.member_account (
USERNAME, PASSWORD, SALT,
CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME
)
VALUES (
#{username}, #{password}, #{salt},
#{create_by}, NOW(), #{update_by}, NOW()
)
</insert>
<select id="findMemberAccountByUsername" parameterType="string" resultType="com.example.demo.entity.MemberAccount">
SELECT
ID, USERNAME, PASSWORD, SALT
FROM
test_project.member_account
WHERE
USERNAME = #{username}
</select>
<update id="update" parameterType="com.example.demo.entity.MemberAccount">
UPDATE
test_project.member_account
SET
PASSWORD = #{password}, UPDATE_BY = #{update_by}, UPDATE_TIME = NOW()
WHERE
ID = #{id}
</update>
</mapper>
使用MyBatis 註解方式建立持久層及其測試方法
使用MyBatis XML方式建立持久層及其測試方法
ORM介紹及ORM優點、缺點
SpringBoot - 第十五章 | MyBatis整合 (註解方式) | J.J.'s Blogs
SpringBoot - 第十六章 | MyBatis整合 (XML方式) | J.J.'s Blogs
SpringBoot + MyBatis(註解版),常用的SQL方法