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("[email protected]");
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 = "[email protected]";
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("[email protected]");
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方法
<<: AI ninja project [day 27] QLattice --进阶分类
>>: Day12 SwiftUI 05 - Life Cycle - SwiftUI App
「钱多事少离家近、睡觉睡到自然醒、位高权重责任轻;老板说话不用听、五年就领退休金、领钱领到手抽筋。」...
Day 29 - Android Studio 这几天以来的统整 离我们铁人完赛只剩一天了,我今天就...
今天邀请到来自新化高中的 Colten 来分享他在高中竞程这条路上的种种历程。本次访谈有公开浏览,欢...
最近刚好在开发 遇到放置图片和logo的问题 所以特别上来写一篇文章 纪录自己最近学习到的新东西 i...
前两天介绍两个以VPN以点对点加密方式连回我们所架设的网路。但这里有个问题是我们得具有硬体与实体IP...