springboot2——MyBatis入门
原生缺陷:
? ? ? ?數(shù)據(jù)庫dao層操作缺陷:
? ? ? ? ? ? ? ?①jdbc的增刪改查代碼的冗余過大,查詢的時候需要遍歷。
? ? ? ? ? ? ? ?②Sql語句和數(shù)據(jù)庫相關(guān)參數(shù)和代碼的耦合性過高。
? ? ? ? ? ? ? ?解決:使用Mybatis
? ? ? ?業(yè)務(wù)層缺陷:
? ? ? ? ? ? ? ?①業(yè)務(wù)層和數(shù)據(jù)庫層的耦合性過高。
? ? ? ? ? ? ? ?②業(yè)務(wù)復(fù)雜,一個業(yè)務(wù)方法中的數(shù)據(jù)庫操作要在一個事務(wù)管理內(nèi)。
? ? ? ? ? ? ? ?解決:使用Spring ? ? ? ?
? ? ? ?控制層缺陷:
? ? ? ? ? ? ? ?①請求數(shù)據(jù)的獲取以及強轉(zhuǎn)
? ? ? ? ? ? ? ?②請求數(shù)據(jù)封裝對象
? ? ? ? ? ? ? ?解決:使用SpringMVC ? ? ? ?
本文講述mybatis? ? ? ? ? ? ? ?
什么是 MyBatis?
MyBatis 是一款優(yōu)秀的持久層框架,它支持定制化 SQL、存儲過程以及高級映射。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設(shè)置參數(shù)以及獲取結(jié)果集。MyBatis 可以使用簡單的 XML 或注解來配置和映射原生類型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 對象)為數(shù)據(jù)庫中的記錄。
安裝
要使用 MyBatis, 只需將?mybatis-x.x.x.jar?文件置于 classpath 中即可。
如果使用 Maven 來構(gòu)建項目,則需將下面的 dependency 代碼置于 pom.xml 文件中:
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>x.x.x</version> </dependency>從 XML 中構(gòu)建 SqlSessionFactory
每個基于 MyBatis 的應(yīng)用都是以一個 SqlSessionFactory 的實例為核心的。SqlSessionFactory 的實例可以通過 SqlSessionFactoryBuilder 獲得。而 SqlSessionFactoryBuilder 則可以從 XML 配置文件或一個預(yù)先定制的 Configuration 的實例構(gòu)建出 SqlSessionFactory 的實例。
從 XML 文件中構(gòu)建 SqlSessionFactory 的實例非常簡單,建議使用類路徑下的資源文件進行配置。 但是也可以使用任意的輸入流(InputStream)實例,包括字符串形式的文件路徑或者 file:// 的 URL 形式的文件路徑來配置。MyBatis 包含一個名叫 Resources 的工具類,它包含一些實用方法,可使從 classpath 或其他位置加載資源文件更加容易。
String resource = "org/mybatis/example/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);XML 配置文件中包含了對 MyBatis 系統(tǒng)的核心設(shè)置,包含獲取數(shù)據(jù)庫連接實例的數(shù)據(jù)源(DataSource)和決定事務(wù)作用域和控制方式的事務(wù)管理器(TransactionManager)。 XML 配置文件的詳細內(nèi)容后面再探討,這里先給出一個簡單的示例:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment></environments><mappers><mapper resource="org/mybatis/example/BlogMapper.xml"/></mappers> </configuration>當然,還有很多可以在 XML 文件中進行配置,上面的示例指出的則是最關(guān)鍵的部分。 要注意 XML 頭部的聲明,它用來驗證 XML 文檔正確性。environment 元素體中包含了事務(wù)管理和連接池的配置。mappers 元素則是包含一組映射器(mapper),這些映射器的 XML 映射文件包含了 SQL 代碼和映射定義信息。
核心組件
生命周期
SqlSessionFactoryBuilder
這個類可以被實例化、使用和丟棄,一旦創(chuàng)建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 實例的最佳作用域是方法作用域(也就是局部方法變量)。 你可以重用 SqlSessionFactoryBuilder 來創(chuàng)建多個 SqlSessionFactory 實例,但是最好還是不要讓其一直存在,以保證所有的 XML 解析資源可以被釋放給更重要的事情。
SqlSessionFactory
SqlSessionFactory 一旦被創(chuàng)建就應(yīng)該在應(yīng)用的運行期間一直存在,沒有任何理由丟棄它或重新創(chuàng)建另一個實例。 使用 SqlSessionFactory 的最佳實踐是在應(yīng)用運行期間不要重復(fù)創(chuàng)建多次,多次重建 SqlSessionFactory 被視為一種代碼“壞味道(bad smell)”。因此 SqlSessionFactory 的最佳作用域是應(yīng)用作用域。 有很多方法可以做到,最簡單的就是使用單例模式或者靜態(tài)單例模式。
SqlSession
每個線程都應(yīng)該有它自己的 SqlSession 實例。SqlSession 的實例不是線程安全的,因此是不能被共享的,所以它的最佳的作用域是請求或方法作用域。 絕對不能將 SqlSession 實例的引用放在一個類的靜態(tài)域,甚至一個類的實例變量也不行。 也絕不能將 SqlSession 實例的引用放在任何類型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你現(xiàn)在正在使用一種 Web 框架,要考慮 SqlSession 放在一個和 HTTP 請求對象相似的作用域中。 換句話說,每次收到的 HTTP 請求,就可以打開一個 SqlSession,返回一個響應(yīng),就關(guān)閉它。 這個關(guān)閉操作是很重要的,你應(yīng)該把這個關(guān)閉操作放到 finally 塊中以確保每次都能執(zhí)行關(guān)閉。 下面的示例就是一個確保 SqlSession 關(guān)閉的標準模式:
try (SqlSession session = sqlSessionFactory.openSession()) {// 你的應(yīng)用邏輯代碼 }在你的所有的代碼中一致地使用這種模式來保證所有數(shù)據(jù)庫資源都能被正確地關(guān)閉。
SpringBoot-mabatis實現(xiàn)用戶增刪改查
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.0.1</version></dependency>mysql和mybatis在springboot中的常用配置介紹
# DataSourceProperties spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/community?characterEncoding=utf-8&useSSL=false&serverTimezone=Hongkong spring.datasource.username=root#賬號 spring.datasource.password=ytywan1314#密碼 spring.datasource.type=com.zaxxer.hikari.HikariDataSource spring.datasource.hikari.maximum-pool-size=15#最大連接數(shù) spring.datasource.hikari.minimum-idle=5#最小空閑 spring.datasource.hikari.idle-timeout=30000#超時時間# MybatisProperties mybatis.mapper-locations=classpath:mapper/*.xml#映射文件的路徑 mybatis.type-aliases-package=com.now.community.community.entity#實體類所在包 mybatis.configuration.useGeneratedKeys=true#自動主鍵 mybatis.configuration.mapUnderscoreToCamelCase=true#實體類和表屬性命名自動對應(yīng),駝峰對應(yīng)下劃線我們寫一下實體類:
package com.now.community.community.entity;import java.util.Date;public class User {private int id;private String username;private String password;private String salt;private String email;private int type;private int status;private String activationCode;private String headerUrl;private Date createTime;@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +", salt='" + salt + '\'' +", email='" + email + '\'' +", type=" + type +", status=" + status +", activationCode='" + activationCode + '\'' +", headerUrl='" + headerUrl + '\'' +", createTime=" + createTime +'}';}public int getId() {return id;}public void setId(int 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 String getSalt() {return salt;}public void setSalt(String salt) {this.salt = salt;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public int getType() {return type;}public void setType(int type) {this.type = type;}public int getStatus() {return status;}public void setStatus(int status) {this.status = status;}public String getActivationCode() {return activationCode;}public void setActivationCode(String activationCode) {this.activationCode = activationCode;}public String getHeaderUrl() {return headerUrl;}public void setHeaderUrl(String headerUrl) {this.headerUrl = headerUrl;}public Date getCreateTime() {return createTime;}public void setCreateTime(Date createTime) {this.createTime = createTime;} }對應(yīng)的表
CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(50) DEFAULT NULL,`password` varchar(50) DEFAULT NULL,`salt` varchar(50) DEFAULT NULL,`email` varchar(100) DEFAULT NULL,`type` int(11) DEFAULT NULL COMMENT '0-普通用戶; 1-超級管理員; 2-版主;',`status` int(11) DEFAULT NULL COMMENT '0-未激活; 1-已激活;',`activation_code` varchar(100) DEFAULT NULL,`header_url` varchar(200) DEFAULT NULL,`create_time` timestamp NULL DEFAULT NULL,PRIMARY KEY (`id`),KEY `index_username` (`username`(20)),KEY `index_email` (`email`(20)) ) ENGINE=InnoDB AUTO_INCREMENT=164 DEFAULT CHARSET=utf8我們寫一個dao層的bean
@Mapper public interface UserMapper {User selectById(int id);User selectByName(String useName);User selectByEmail(String email);int insertUser(User user);int updateStatus(int id,int status);int updateHeader(int id,String headerUrl);int updatePassword(int id,String password);}XML 映射文件
MyBatis 的真正強大在于它的映射語句,這是它的魔力所在。由于它的異常強大,映射器的 XML 文件就顯得相對簡單。如果拿它跟具有相同功能的 JDBC 代碼進行對比,你會立即發(fā)現(xiàn)省掉了將近 95% 的代碼。MyBatis 為聚焦于 SQL 而構(gòu)建,以盡可能地為你減少麻煩。
SQL 映射文件只有很少的幾個頂級元素(按照應(yīng)被定義的順序列出):
- cache?– 對給定命名空間的緩存配置。
- cache-ref?– 對其他命名空間緩存配置的引用。
- resultMap?– 是最復(fù)雜也是最強大的元素,用來描述如何從數(shù)據(jù)庫結(jié)果集中來加載對象。
- parameterMap?– 已被廢棄!老式風(fēng)格的參數(shù)映射。更好的辦法是使用內(nèi)聯(lián)參數(shù),此元素可能在將來被移除。文檔中不會介紹此元素。
- sql?– 可被其他語句引用的可重用語句塊。
- insert?– 映射插入語句
- update?– 映射更新語句
- delete?– 映射刪除語句
- select?– 映射查詢語句
select
查詢語句是 MyBatis 中最常用的元素之一,光能把數(shù)據(jù)存到數(shù)據(jù)庫中價值并不大,只有還能重新取出來才有用,多數(shù)應(yīng)用也都是查詢比修改要頻繁。對每個插入、更新或刪除操作,通常間隔多個查詢操作。這是 MyBatis 的基本原則之一,也是將焦點和努力放在查詢和結(jié)果映射的原因。簡單查詢的 select 元素是非常簡單的。比如:
<select id="selectPerson" parameterType="int" resultType="hashmap">SELECT * FROM PERSON WHERE ID = #{id} </select>這個語句被稱作 selectPerson,接受一個 int(或 Integer)類型的參數(shù),并返回一個 HashMap 類型的對象,其中的鍵是列名,值便是結(jié)果行中的對應(yīng)值。
注意參數(shù)符號:
#{id}這就告訴 MyBatis 創(chuàng)建一個預(yù)處理語句(PreparedStatement)參數(shù),在 JDBC 中,這樣的一個參數(shù)在 SQL 中會由一個“?”來標識,并被傳遞到一個新的預(yù)處理語句中,就像這樣:
// 近似的 JDBC 代碼,非 MyBatis 代碼... String selectPerson = "SELECT * FROM PERSON WHERE ID=?"; PreparedStatement ps = conn.prepareStatement(selectPerson); ps.setInt(1,id);當然,使用 JDBC 意味著需要更多的代碼來提取結(jié)果并將它們映射到對象實例中,而這就是 MyBatis 節(jié)省你時間的地方。參數(shù)和結(jié)果映射還有更深入的細節(jié)。這些細節(jié)會分別在后面單獨的小節(jié)中呈現(xiàn)。
select 元素允許你配置很多屬性來配置每條語句的作用細節(jié)。
<selectid="selectPerson"parameterType="int"parameterMap="deprecated"resultType="hashmap"resultMap="personResultMap"flushCache="false"useCache="true"timeout="10"fetchSize="256"statementType="PREPARED"resultSetType="FORWARD_ONLY">| id | 在命名空間中唯一的標識符,可以被用來引用這條語句。 |
| parameterType | 將會傳入這條語句的參數(shù)類的完全限定名或別名。這個屬性是可選的,因為 MyBatis 可以通過類型處理器(TypeHandler) 推斷出具體傳入語句的參數(shù),默認值為未設(shè)置(unset)。 |
| parameterMap | 這是引用外部 parameterMap 的已經(jīng)被廢棄的方法。請使用內(nèi)聯(lián)參數(shù)映射和 parameterType 屬性。 |
| resultType | 從這條語句中返回的期望類型的類的完全限定名或別名。 注意如果返回的是集合,那應(yīng)該設(shè)置為集合包含的類型,而不是集合本身。可以使用 resultType 或 resultMap,但不能同時使用。 |
| resultMap | 外部 resultMap 的命名引用。結(jié)果集的映射是 MyBatis 最強大的特性,如果你對其理解透徹,許多復(fù)雜映射的情形都能迎刃而解??梢允褂?resultMap 或 resultType,但不能同時使用。 |
| flushCache | 將其設(shè)置為 true 后,只要語句被調(diào)用,都會導(dǎo)致本地緩存和二級緩存被清空,默認值:false。 |
| useCache | 將其設(shè)置為 true 后,將會導(dǎo)致本條語句的結(jié)果被二級緩存緩存起來,默認值:對 select 元素為 true。 |
| timeout | 這個設(shè)置是在拋出異常之前,驅(qū)動程序等待數(shù)據(jù)庫返回請求結(jié)果的秒數(shù)。默認值為未設(shè)置(unset)(依賴驅(qū)動)。 |
| fetchSize | 這是一個給驅(qū)動的提示,嘗試讓驅(qū)動程序每次批量返回的結(jié)果行數(shù)和這個設(shè)置值相等。 默認值為未設(shè)置(unset)(依賴驅(qū)動)。 |
| statementType | STATEMENT,PREPARED 或 CALLABLE 中的一個。這會讓 MyBatis 分別使用 Statement,PreparedStatement 或 CallableStatement,默認值:PREPARED。 |
| resultSetType | FORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等價于 unset) 中的一個,默認值為 unset (依賴驅(qū)動)。 |
| databaseId | 如果配置了數(shù)據(jù)庫廠商標識(databaseIdProvider),MyBatis 會加載所有的不帶 databaseId 或匹配當前 databaseId 的語句;如果帶或者不帶的語句都有,則不帶的會被忽略。 |
| resultOrdered | 這個設(shè)置僅針對嵌套結(jié)果 select 語句適用:如果為 true,就是假設(shè)包含了嵌套結(jié)果集或是分組,這樣的話當返回一個主結(jié)果行的時候,就不會發(fā)生有對前面結(jié)果集的引用的情況。 這就使得在獲取嵌套的結(jié)果集的時候不至于導(dǎo)致內(nèi)存不夠用。默認值:false。 |
| resultSets | 這個設(shè)置僅對多結(jié)果集的情況適用。它將列出語句執(zhí)行后返回的結(jié)果集并給每個結(jié)果集一個名稱,名稱是逗號分隔的。 |
insert, update 和 delete
數(shù)據(jù)變更語句 insert,update 和 delete 的實現(xiàn)非常接近:
<insertid="insertAuthor"parameterType="domain.blog.Author"flushCache="true"statementType="PREPARED"keyProperty=""keyColumn=""useGeneratedKeys=""timeout="20"><updateid="updateAuthor"parameterType="domain.blog.Author"flushCache="true"statementType="PREPARED"timeout="20"><deleteid="deleteAuthor"parameterType="domain.blog.Author"flushCache="true"statementType="PREPARED"timeout="20">| id | 命名空間中的唯一標識符,可被用來代表這條語句。 |
| parameterType | 將要傳入語句的參數(shù)的完全限定類名或別名。這個屬性是可選的,因為 MyBatis 可以通過類型處理器推斷出具體傳入語句的參數(shù),默認值為未設(shè)置(unset)。 |
| parameterMap | 這是引用外部 parameterMap 的已經(jīng)被廢棄的方法。請使用內(nèi)聯(lián)參數(shù)映射和 parameterType 屬性。 |
| flushCache | 將其設(shè)置為 true 后,只要語句被調(diào)用,都會導(dǎo)致本地緩存和二級緩存被清空,默認值:true(對于 insert、update 和 delete 語句)。 |
| timeout | 這個設(shè)置是在拋出異常之前,驅(qū)動程序等待數(shù)據(jù)庫返回請求結(jié)果的秒數(shù)。默認值為未設(shè)置(unset)(依賴驅(qū)動)。 |
| statementType | STATEMENT,PREPARED 或 CALLABLE 的一個。這會讓 MyBatis 分別使用 Statement,PreparedStatement 或 CallableStatement,默認值:PREPARED。 |
| useGeneratedKeys | (僅對 insert 和 update 有用)這會令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法來取出由數(shù)據(jù)庫內(nèi)部生成的主鍵(比如:像 MySQL 和 SQL Server 這樣的關(guān)系數(shù)據(jù)庫管理系統(tǒng)的自動遞增字段),默認值:false。 |
| keyProperty | (僅對 insert 和 update 有用)唯一標記一個屬性,MyBatis 會通過 getGeneratedKeys 的返回值或者通過 insert 語句的 selectKey 子元素設(shè)置它的鍵值,默認值:未設(shè)置(unset)。如果希望得到多個生成的列,也可以是逗號分隔的屬性名稱列表。 |
| keyColumn | (僅對 insert 和 update 有用)通過生成的鍵值設(shè)置表中的列名,這個設(shè)置僅在某些數(shù)據(jù)庫(像 PostgreSQL)是必須的,當主鍵列不是表中的第一列的時候需要設(shè)置。如果希望使用多個生成的列,也可以設(shè)置為逗號分隔的屬性名稱列表。 |
| databaseId | 如果配置了數(shù)據(jù)庫廠商標識(databaseIdProvider),MyBatis 會加載所有的不帶 databaseId 或匹配當前 databaseId 的語句;如果帶或者不帶的語句都有,則不帶的會被忽略。 |
sql
這個元素可以被用來定義可重用的 SQL 代碼段,這些 SQL 代碼可以被包含在其他語句中。它可以(在加載的時候)被靜態(tài)地設(shè)置參數(shù)。 在不同的包含語句中可以設(shè)置不同的值到參數(shù)占位符上。比如:
<sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql>這個 SQL 片段可以被包含在其他語句中,例如:
<select id="selectUsers" resultType="map">select<include refid="userColumns"><property name="alias" value="t1"/></include>,<include refid="userColumns"><property name="alias" value="t2"/></include>from some_table t1cross join some_table t2 </select>然后我們根據(jù)剛才的知識寫對應(yīng)的配置文件:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.now.community.community.dao.UserMapper"><sql id="insertFields">userName,password,salt,email,type,status,activation_code,header_url,create_time</sql><sql id="selectFields">id,userName,password,salt,email,type,status,activation_code,header_url,create_time</sql><select id="selectById" resultType="User">select <include refid="selectFields"></include>from userwhere id=#{id}</select><select id="selectByName" resultType="User">select <include refid="selectFields"></include>from userwhere username=#{username}</select><select id="selectByEmail" resultType="User">select <include refid="selectFields"></include>from userwhere email=#{email}</select><insert id="insertUser" parameterType="User" keyProperty="id">insert into user (<include refid="insertFields"></include>)values(#{username},#{password},#{salt},#{email},#{type},#{status},#{activationCode},#{headerUrl},#{createTime})</insert><update id="updateStatus">update user set status=#{status} where id=#{id}</update><update id="updateHeader">update user set header_url=#{headerUrl} where id=#{id}</update><update id="updatePassword">update user set password=#{password} where id=#{id}</update></mapper>測試效果
@RunWith(SpringRunner.class) @SpringBootTest @ContextConfiguration(classes = CommunityApplication.class) public class MapperTests {@Autowiredprivate UserMapper userMapper;@Testpublic void testSelectUser(){User user=userMapper.selectById(101);System.out.println(user);user = userMapper.selectByName("liubei");System.out.println(user);user = userMapper.selectByEmail("101@sina.com");System.out.println(user);}@Testpublic void testInsertUser() {User user = new User();user.setUsername("test");user.setPassword("123456");user.setSalt("abc");user.setEmail("test@qq.com");user.setHeaderUrl("E:/101.png");user.setCreateTime(new Date());System.out.println(user.toString());int rows = userMapper.insertUser(user);System.out.println(rows);System.out.println(user.getId());}@Testpublic void updateUser() {int rows = userMapper.updateStatus(150, 1);System.out.println(rows);rows = userMapper.updateHeader(150, "E:/102.png");System.out.println(rows);rows = userMapper.updatePassword(150, "hello");System.out.println(rows);} }可以查看結(jié)果是完全沒問題的
總結(jié)
以上是生活随笔為你收集整理的springboot2——MyBatis入门的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springboot——概述
- 下一篇: 手把手maven的功能/安装/使用/id