iT邦幫忙

2021 iThome 鐵人賽

DAY 12
1

MyBatis 可以簡單的使用註解XML 的方式進行配置和對映,通過將引數對映到配置的SQL 形成最終執行的SQL 語法最後將SQL 語法執行結果對映成Java 物件返回

在開始實作功能以前,我們會先簡單介紹一下ORM 以及它的優缺點,再來展示如何實作註解及XML 兩種使用方式,而實作的功能與上一篇Day 11 - Spring Boot & JdbcTemplate一樣。

ORM

ORM,全名為Object Relational Mapping,中文名稱為物件關係對映目的是為了解決面向物件與關聯式資料庫中資料類型互不匹配的問題,它的作法是在實體物件和關聯式資料庫之間做一個映射,這樣在操作實體物件時就不需要使用複雜的SQL 語法,只需要操作物件的屬性和方法。

優點

  1. 解決操作資料庫的重複性
    我們對資料庫的操作無非就是增、刪、改、查四種操作,但當我們在實作持久層時,我們還是需要寫大量的程式碼,只因為我們操作的資料表不同,而使用ORM 則可以自動生成CRUD 語法,開發時就可以把更多的精力放在業務邏輯上。

  2. 增加應用程式的擴展性和靈活性並防止SQL 注入
    當我們在編寫持久層邏輯時,如果操作的是MySQL 資料庫時,我們就會使用相應的語法以及配置,但當我們需要更換資料庫時,整個持久層的邏輯就需要重新編寫。

    而ORM 做到了實體物件與資料庫之間的映射,ORM 可以通過映射關係自動生成SQL 語法,因此不必再編寫重複的程式碼且不用擔心SQL 注入的問題。

缺點

  1. 自動化進行實體物件與資料庫之間的映射代價就是消耗系統性能
  2. 在處理多表查詢或是where 條件複雜查詢時,ORM 語法會變得更加複雜。

MyBatis 常用註釋

CRUD 註釋

  • @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);		
	}
	
}

實作XML 方式

指定XML 檔案位置

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);
	
}

設定掃描持久層(Mapper)的路徑

在上一個步驟定義持久層接口時並沒有定義@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 檔案

<?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>

Github

使用MyBatis 註解方式建立持久層及其測試方法
使用MyBatis XML方式建立持久層及其測試方法

參考網站

ORM介紹及ORM優點、缺點
SpringBoot - 第十五章 | MyBatis整合 (註解方式) | J.J.'s Blogs
SpringBoot - 第十六章 | MyBatis整合 (XML方式) | J.J.'s Blogs
SpringBoot + MyBatis(註解版),常用的SQL方法


上一篇
Day 11 - Spring Boot & JdbcTemplate
下一篇
Day 13 - Spring Boot & JPA
系列文
誤打誤撞學了Spring Boot 還當了後端工程師30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言