本篇博客介紹 MyBatis 基於注解配置 SQL 語句的實現方式,這種實現方式非常簡單方便,我個人也比較喜歡這種方式。在實際的企業開發中,注解的實現方式也比 XML 的實現方式要多一些。還是那句話:具體采用哪種方式取決於公司的開發規定,建議兩種開發方式都要掌握。
MyBatis 的官網地址為:https://mybatis.org/mybatis-3/zh/sqlmap-xml.html
本篇博客以上篇博客中的 demo 為基礎,把基於 XML 配置 SQL 語句的實現方式,改造成基於注解配置 SQL 的實現方式,最終實現的效果一模一樣。在本篇博客的最后面,將會提供源代碼。
一、導入 jar 包
新建一個 Maven 項目,在 pom.xml 文件中導入 4 個 jar 包:
mysql 的 jar 包:https://mvnrepository.com/artifact/mysql/mysql-connector-java
mybatis 的 jar 包:https://mvnrepository.com/artifact/org.mybatis/mybatis
log4j 的 jar 包:https://mvnrepository.com/artifact/log4j/log4j
junit 的 jar 包:https://mvnrepository.com/artifact/junit/junit
我在 pom.xml 配置的都是當前最新版本的 jar 包,如下所示:
<!--導入 mysql 的 jar 包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!--導入 mybatis 的 jar 包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<!--導入 log4j 的 jar 包-->
<!--主要是為了查看 mybatis 生成的最終 sql 語句-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--導入 junit 的 jar 包-->
<!--方便編寫測試方法,對 mybatis 操作數據庫進行測試-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
配置好引用的 jar 包后,打開右側的 Maven 窗口,刷新一下,這樣 Maven 會自動下載所需的 jar 包文件。
二、搭建整個工程
整個項目工程的結構和整體內容,如下圖所示,
項目工程結構簡單介紹:
com.jobs.bean 包下存放的是實體類
com.jobs.mapper 包下存放的是 Mybatis 操作數據庫的接口
com.jobs.mapper.sql 包下存放的是給注解提供 SQL 語句的方法實現類
com.jobs.service 包下存放的是使用 Mybatis 的類庫操作數據的業務方法
resources 目錄下的配置文件介紹:
jdbc.properties 是數據庫連接參數的文件
log4j.properties 是配置 log4j 日志輸出參數的文件
MyBatisConfig.xml 是 MyBatis 的核心配置文件
test 目錄下的文件介紹:
com.jobs.employeeTest 類是專門用來編寫 junit 單元測試方法的,用來測試 MyBatis 是否搭建成功
三、編寫配置文件內容
jdbc.properties 文件配置數據庫連接信息,內容如下:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/testdb
username=root
password=123456
log4j.properties 文件配置控制台日志輸出的信息,內容如下:
# 輸出 debug 以上的所有類型的日志信息(DEBUG INFO WARN ERROR FATAL)
# stdout 配置項的名稱(表明使用下面的 log4j.appender.stdout 對應的配置)
log4j.rootLogger=DEBUG, stdout
# log4j.appender.stdout 配置的是控制台輸出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
# 該項配置表示要自定義日志顯示的格式
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# 自定義日志顯示格式:
# %p 表示輸出每條日志的級別信息(DEBUG INFO WARN ERROR FATAL)
# %t 表示輸出產生日志的線程的名稱
# %m 表示輸出具體的日志信息
# %n 表示根據當前操作系統類型,輸出一個回車換行
log4j.appender.stdout.layout.ConversionPattern=%p [%t] - %m%n
MyBatisConfig.xml 文件是 MyBatis 的核心配置文件,配置內容如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!--引入MyBatis 的 DTD 約束-->
<!DOCTYPE configuration PUBLIC
"-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--引入數據庫連接的配置文件-->
<properties resource="jdbc.properties"/>
<!--引入 log4j 日志,方便查看運行過程中所生成的 sql 語句-->
<settings>
<setting name="logImpl" value="log4j"/>
</settings>
<!--為實體類 bean 起別名,這樣就可以在 SQL 配置文件中直接使用 bean 的類名代替全限定類名-->
<typeAliases>
<!--使用 package 將指定包下的所有類進行自動取別名-->
<package name="com.jobs.bean"/>
</typeAliases>
<!--environments 配置數據庫環境,環境可以有多個。default 屬性指定使用的是哪個-->
<environments default="mysql">
<!--environment配置數據庫環境,id屬性唯一標識-->
<environment id="mysql">
<!--transactionManager 事務管理,這里采用 JDBC 默認的事務-->
<transactionManager type="JDBC"></transactionManager>
<!--dataSource 數據源信息,這里采用連接池-->
<dataSource type="POOLED">
<!--通過引入的 jdbc.properties 文件中的 key 獲取數據庫連接的配置信息-->
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<!-- mappers 引入操作數據庫的接口映射配置文件 -->
<mappers>
<!--使用 package 將指定包下的所有類進行自動映射-->
<package name="com.jobs.mapper"/>
</mappers>
</configuration>
相比於 XML 配置 SQL 語句的實現方式,基於注解配置 SQL 語句的實現方式,對 MyBatis 核心配置文件的更改,只在最后面的 mappers 配置上有差別,其配置的是具體的 mapper 接口所在的包。
四、數據庫表和實體類
MySQL 數據庫下創建了 testdb 數據庫,里面創建了一張 employee 表,具體 SQL 語句如下:
-- 創建數據庫
CREATE DATABASE IF NOT EXISTS `testdb`;
USE `testdb`;
-- 創建表
CREATE TABLE IF NOT EXISTS `employee` (
`e_id` int(11) NOT NULL AUTO_INCREMENT,
`e_name` varchar(50) DEFAULT NULL,
`e_age` int(11) DEFAULT NULL,
PRIMARY KEY (`e_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
-- 向表中添加數據
INSERT INTO `employee` (`e_id`, `e_name`, `e_age`)
VALUES(1, '侯胖胖', 25),(2, '楊磅磅', 23),
(3, '李噸噸', 33),(4, '任肥肥', 35),(5, '喬豆豆', 32);
com.jobs.bean.employee 實體類的內容如下:(這里故意讓【實體類的字段】與【數據庫的字段】名稱不一樣)
package com.jobs.bean;
public class employee {
//主鍵id
private Integer id;
//姓名
private String name;
//年齡
private Integer age;
public employee() {
}
public employee(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
//方便將員工信息在控制台打印出來查看
@Override
public String toString() {
return "employee{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
五、編寫提供 SQL 語句類
對於一些比較復雜的 SQL 語句,不太方便使用注解進行直接編寫,最佳方案就是通過調用一個方法進行獲取,因此這里在 com.jobs.mapper.sql 包下的 employeeMapperSQL 類中編寫兩個方法,分別用於獲取【根據條件查詢】和【根據多 id 查詢】兩個比較復雜的 SQL 語句,內容如下:
package com.jobs.mapper.sql;
import com.jobs.bean.employee;
import java.util.List;
public class employeeMapperSQL {
//獲取條件查詢的動態拼接 SQL 語句
public String getSelectConditionSQL(employee ele) {
StringBuilder sb = new StringBuilder();
sb.append("select e_id,e_name,e_age from employee");
if (ele != null) {
sb.append(" where 1=1");
if (ele.getId() != null) {
sb.append(" and e_id=#{id}");
}
if (ele.getName() != null) {
sb.append(" and e_name like CONCAT('%',#{name},'%')");
}
if (ele.getAge() != null) {
sb.append(" and e_age = #{age}");
}
}
sb.append(" order by e_id desc");
return sb.toString();
}
//獲取多個id查詢條件拼接后的 SQL 語句
public String getSelectByIdsSQL(List<Integer> ids) {
StringBuilder sb = new StringBuilder();
sb.append("select e_id,e_name,e_age from employee");
if (ids != null && ids.size() > 0) {
sb.append(" where e_id in (");
for (int i = 0; i < ids.size(); i++) {
if (i == 0) {
sb.append(ids.get(0));
} else {
sb.append(",").append(ids.get(i));
}
}
sb.append(")");
}
return sb.toString();
}
}
六、在 Mapper 接口上通過注解配置 SQL 語句
下面列出 com.jobs.mapper.employeeMapper 這個 Mapper 接口 的內容:
package com.jobs.mapper;
import com.jobs.bean.employee;
import com.jobs.mapper.sql.employeeMapperSQL;
import org.apache.ibatis.annotations.*;
import java.util.List;
public interface employeeMapper {
//查詢全部
@Results(id="employee_map",value = {
@Result(column = "e_id",property = "id"),
@Result(column = "e_name",property = "name"),
@Result(column = "e_age",property = "age")})
@Select("select e_id,e_name,e_age from employee order by e_id")
List<employee> selectAll();
//根據id查詢
@ResultMap("employee_map")
@Select("select e_id,e_name,e_age from employee where e_id = #{id}")
employee selectById(Integer id);
//新增數據
@Insert("insert into employee(e_id,e_name,e_age) values(#{id},#{name},#{age})")
Integer insert(employee ele);
//修改數據
@Update("update employee SET e_name=#{name},e_age=#{age} where e_id = #{id}")
Integer update(employee ele);
//刪除數據
@Delete("delete FROM employee where e_id = #{id}")
Integer delete(Integer id);
//根據條件查詢
@ResultMap("employee_map")
@SelectProvider(type = employeeMapperSQL.class , method = "getSelectConditionSQL")
List<employee> selectCondition(employee ele);
//根據多個id查詢
@ResultMap("employee_map")
@SelectProvider(type = employeeMapperSQL.class , method = "getSelectByIdsSQL")
List<employee> selectByIds(List<Integer> ids);
}
由於我們故意讓數據庫中的 employee 表字段名稱與 java 的實體類 bean 中的 employee 字段名稱不一致,所以這里需要使用 @Results 注解建立數據庫字段與實體類字段的對應關系,並給與一個 id 值 employee_map 。建立好關系之后,其它方法如果返回結果也是 employee 類型的話,可以通過 @ResultMap("employee_map") 引用建立好的對應關系,非常方便。
對於 selectCondition 和 selectByIds 兩個接口方法,由於其使用的 SQL 語句比較復雜,因此不太方便直接在注解上進行編寫,所以通過 @SelectProvider 注解去引用 employeeMapperSQL 類中的對應方法,非常方便。
六、編寫 Service 方法訪問數據庫
Service 里面的方法定義可以與 Mapper 接口中的方法不一樣,這里為了方便,就保持一致了。
com.jobs.service.employeeService 的內容如下所示:
package com.jobs.service;
import com.jobs.bean.employee;
import com.jobs.mapper.employeeMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class employeeService {
//查詢所有
public List<employee> selectAll() {
List<employee> list = null;
SqlSession sqlSession = null;
InputStream is = null;
try {
//加載核心配置文件
is = Resources.getResourceAsStream("MyBatisConfig.xml");
//獲取SqlSession工廠對象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//通過工廠對象獲取SqlSession對象,openSession 的參數為 true 表示自動提交事務
//對於增刪改操作,如果 openSession 為 false,
//在程序代碼最后需要通過 sqlSession.commit() 提交事務,才能使寫操作生效
sqlSession = sqlSessionFactory.openSession(true);
//通過動態代理獲取StudentMapper接口的實現類對象
employeeMapper mapper = sqlSession.getMapper(employeeMapper.class);
//調用接口方法
list = mapper.selectAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return list;
}
//根據id查詢單個員工
public employee selectById(Integer id) {
employee ele = null;
SqlSession sqlSession = null;
InputStream is = null;
try {
is = Resources.getResourceAsStream("MyBatisConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
sqlSession = sqlSessionFactory.openSession(true);
employeeMapper mapper = sqlSession.getMapper(employeeMapper.class);
ele = mapper.selectById(id);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return ele;
}
//新增
public Integer insert(employee ele) {
Integer result = null;
SqlSession sqlSession = null;
InputStream is = null;
try {
is = Resources.getResourceAsStream("MyBatisConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
sqlSession = sqlSessionFactory.openSession(true);
employeeMapper mapper = sqlSession.getMapper(employeeMapper.class);
result = mapper.insert(ele);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
//修改
public Integer update(employee ele) {
Integer result = null;
SqlSession sqlSession = null;
InputStream is = null;
try {
is = Resources.getResourceAsStream("MyBatisConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
sqlSession = sqlSessionFactory.openSession(true);
employeeMapper mapper = sqlSession.getMapper(employeeMapper.class);
result = mapper.update(ele);
} catch (Exception e) {
e.printStackTrace();
} finally {
//6.釋放資源
if (sqlSession != null) {
sqlSession.close();
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
//刪除
public Integer delete(Integer id) {
Integer result = null;
SqlSession sqlSession = null;
InputStream is = null;
try {
is = Resources.getResourceAsStream("MyBatisConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
sqlSession = sqlSessionFactory.openSession(true);
employeeMapper mapper = sqlSession.getMapper(employeeMapper.class);
result = mapper.delete(id);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
//根據條件查詢
public List<employee> selectCondition(employee ele) {
List<employee> list = null;
SqlSession sqlSession = null;
InputStream is = null;
try {
is = Resources.getResourceAsStream("MyBatisConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
sqlSession = sqlSessionFactory.openSession(true);
employeeMapper mapper = sqlSession.getMapper(employeeMapper.class);
list = mapper.selectCondition(ele);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return list;
}
//根據多個id查詢
public List<employee> selectByIds(List<Integer> ids) {
List<employee> list = null;
SqlSession sqlSession = null;
InputStream is = null;
try {
is = Resources.getResourceAsStream("MyBatisConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
sqlSession = sqlSessionFactory.openSession(true);
employeeMapper mapper = sqlSession.getMapper(employeeMapper.class);
list = mapper.selectByIds(ids);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return list;
}
}
上面有很多重復代碼,有興趣的話,可以自己進行一下封裝。實際上也沒有封裝的必要,因為后面使用 Spring 框架集成了 MyBatis 后,上面的很多代碼根本就不需要寫了。
七、使用 junit 測試驗證
com.jobs.employeeTest 類編寫的測試方法內容如下所示:
package com.jobs;
import com.jobs.bean.employee;
import com.jobs.service.employeeService;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
public class employeeTest {
private employeeService service = new employeeService();
//查詢全部測試
@Test
public void selectAll() {
List<employee> elist = service.selectAll();
for (employee ele : elist) {
System.out.println(ele);
}
}
//根據id查詢測試
@Test
public void selectById() {
employee ele = service.selectById(3);
System.out.println(ele);
}
//新增測試
@Test
public void insert() {
employee ele = new employee(6, "任天蓬", 26);
Integer result = service.insert(ele);
System.out.println(result);
}
//修改測試
@Test
public void update() {
employee ele = new employee(6, "任天蓬", 16);
Integer result = service.update(ele);
System.out.println(result);
}
//根據條件動態生成SQL語句查詢測試
@Test
public void selectCondition() {
//可以同時啟用多個條件,根據條件動態拼接 SQL 語句
employee ele = new employee();
//ele.setId(4); //通過 id 查詢
ele.setName("任"); //通過姓名模糊查詢
//ele.setAge(35); //通過年齡查詢
List<employee> elelist = service.selectCondition(ele);
for (employee empl : elelist) {
System.out.println(empl);
}
}
//根據多個 id 查詢測試
@Test
public void selectByIds() {
ArrayList<Integer> ids = new ArrayList<>(List.of(1,2,3));
List<employee> elelist = service.selectByIds(ids);
for (employee empl : elelist) {
System.out.println(empl);
}
}
//刪除測試
@Test
public void delete() {
Integer result = service.delete(6);
System.out.println(result);
}
}
OK,到此為止, Mybatis 通過注解配置 SQL 語句的實現方式,已經快速介紹完畢,希望對大家有用,源代碼下載地址如下:
https://files.cnblogs.com/files/blogs/699532/MybatisAnnoCode.zip