日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

MyBatis(一)MyBatis介绍和配置详解

發布時間:2024/4/11 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MyBatis(一)MyBatis介绍和配置详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

在Java程序里面去操作數據庫,最原始的辦法是使用JDBC的API。需要分為六步:

  • 注冊驅動
  • 通過DriverManager獲取一個Connection
  • 通過Connection創建一個Statement對象。
  • 通過Statement的execute()方法執行SQL,返回結果集ResultSet
  • 將ResultSet結果集轉換成POJO對象。
  • 關閉各種資源

像Connection獲取,結果集的封裝,資源關閉這些代碼在開發的過程中會出現大量冗余,所以出現了很多對JDBC進行封裝的框架來簡化操作。

Apache DbUtils:
DbUtils 解決的最核心的問題就是結果集的映射,提供了一系列的支持泛型的ResultSetHandler,幫助我們把 ResultSet 封裝成JavaBean。
DbUtils提供了一個QueryRunner類,它對數據庫的增刪改查的方法進行了封裝, 在 QueryRunner 的構造函數里面,我們可以傳入一個數據源DataSource,讓框架幫我們管理連接。

queryRunner = new QueryRunner(dataSource); String sql = "select * from blog"; List<Blog> list = queryRunner.query(sql, new BeanListHandler<>(Blog.class));

注意:DbUtils要求數據庫的字段跟對象的屬性名稱完全一致,才可以實現自動映射。

Spring JDBC
Spring也對原生的JDBC進行了封裝,并且給我們提供了一個模板方法JdbcTemplate,來簡化我們對數據庫的操作。
和dbutils類似,spring幫助我們管理datasource和connection,并且提供了RowMapper接口,我們只要實現RowMapper接口,并且重寫mapRow()方法,就可以將結果集轉換成Java對象。

public class EmployeeRowMapper implements RowMapper {@Overridepublic Object mapRow(ResultSet resultSet, int i) throws SQLException {Employee employee = new Employee();employee.setEmpId(resultSet.getInt("emp_id"));employee.setEmpName(resultSet.getString("emp_name"));employee.setEmail(resultSet.getString("email"));return employee;} }jdbcTemplate = new JdbcTemplate( new DruidDataSource()); list = jdbcTemplate.query(" select * from emp_table", new EmployeeRowMapper());

上面兩種都是對JDBC筆記簡單的封裝,雖然簡化了操作,但是缺少一些擴展功能,比方說SQL語句還是需要在代碼里硬編碼,不便于修改,無法生成動態SQL,沒有緩存等

這就有了功能更加豐富的ORM框架(Object Relational Mapping),幫助我們解決程序對象和關系型數據庫的相互映射的問題。

MyBatis使用

MyBatis 就是一個“半自動化”的ORM框架(一般稱Hibernate為全自動化),它的封裝程度沒有Hibernate那么高,不會自動生成全部的SQL語句,但是相對性能也更好一些 ?(框架封裝的越多,說明內部處理越多,相對來說性能越差,原生的JDBC API的性能反而是最好的)

先看看在單獨使用Mybatis的時候我們是怎么配置的

  • 引入Mybatis jar包
  • 創建一個全局配置文件mybatis-config.xml?
  • 創建映射器文件,Mapper.xml,通常來說一張表對應一個Mapper文件

使用demo

public void Test() throws IOException {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);SqlSession session = sqlSessionFactory.openSession();try {//執行SQL有兩種方法://1.通過SqlSession接口上的方法,傳入Statement ID來執行SQL//2.定義一個Mapper接口。這個接口全路徑必須跟Mapper.xml里面的namespace對應起來,方法也要跟Statement ID一一對應BlogMapper mapper = session.getMapper(BlogMapper.class);Blog blog = mapper.selectBlogById(1);System.out.println(blog);} finally {session.close();}}

從上面的代碼可以看出MyBatis的幾大核心對象:SqlSessionFactoryBuiler、SqlSessionFactory、SqlSession 和Mapper對象

核心對象

1)SqlSessionFactoryBuilder
用來構建 SqlSessionFactory 的(建造者模式),SqlSessionFactory作為會話工廠只需要一個就夠了,所以只要創建了SqlSessionFactory,Builder就可以銷毀了 所以它的生命周期只存在于方法的局部。

2)SqlSessionFactory
SqlSessionFactory 是用來創建SqlSession的,每次應用程序訪問數據庫,都需要創建一個會話。所以 SqlSessionFactory 應該存在于應用的整個生命周期中(作用域是應用作用域),并且是單例的。

3)SqlSession
SqlSession是一個會話,因為它不是線程安全的,所以不能在線程間共享。每次請求開始的時候都需要創建一個SqlSession對象,在請求結束的時候要及時關閉它 ? ?作用域:一次請求或者交互中

4)Mapper
Mapper(實際上是一個代理對象 后面會分析)的作用是發送SQL來操作數據庫,是從SqlSession中獲取的,所以它的作用域應該和SqlSession相關,在一個 SqlSession事務方法之內才有效

對象生命周期
SqlSessionFactoryBuiler方法局部(method)
SqlSessionFactory(單例)應用級別(application)
SqlSession請求和操作(request/method)
Mapper

方法(method)?

?

?

?

?

?

?

核心配置解讀

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration><properties resource="db.properties"></properties><settings><!-- 打印查詢語句 --><setting name="logImpl" value="STDOUT_LOGGING" /><!-- 控制全局緩存(二級緩存)--><setting name="cacheEnabled" value="true"/><!-- 延遲加載的全局開關。當開啟時,所有關聯對象都會延遲加載。默認 false --><setting name="lazyLoadingEnabled" value="true"/><!-- 當開啟時,任何方法的調用都會加載該對象的所有屬性。默認 false,可通過select標簽的 fetchType來覆蓋--><setting name="aggressiveLazyLoading" value="false"/><!-- Mybatis 創建具有延遲加載能力的對象所用到的代理工具,默認JAVASSIST --><!--<setting name="proxyFactory" value="CGLIB" />--><setting name="localCacheScope" value="SESSION"/></settings><typeAliases><typeAlias alias="blog" type="com.chenpp.domain.Blog" /></typeAliases><typeHandlers><typeHandler handler="com.chenpp.type.MyTypeHandler"></typeHandler></typeHandlers><!-- 對象工廠 --> <!-- <objectFactory type="com.chenpp.objectfactory.CPObjectFactory"><property name="name" value="cpp"/></objectFactory>--><!-- <plugins><plugin interceptor="com.chenpp.interceptor.MyPageInterceptor"></plugin></plugins>--><environments default="development"><environment id="development"><transactionManager type="JDBC"/><!-- 單獨使用時配置成MANAGED沒有事務 --><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><mappers><mapper resource="BlogMapper.xml"/></mappers></configuration>

一級標簽

configuration
configuration 是整個配置文件的根標簽,對應?MyBatis 里面最重要的配置類 Configuration(單例)

properties
用來配置參數信息,比如最常見的數據庫連接信息。
為了避免直接把參數寫死在 xml 配置文件中,我們可以把這些參數單獨放在properties 文件中,用 properties 標簽引入進來,然后在xml 配置文件中用${}引用就可以了。

settings
setttings里面是MyBatis的一些核心配置,各種參數的配置
https://mybatis.org/mybatis-3/zh/configuration.html#settings

屬性名?描述有效值默認值
cacheEnabled全局地開啟或關閉配置文件中的所有映射器已經配置的任何緩存。true | falsetrue
lazyLoadingEnabled延遲加載的全局開關。當開啟時,所有關聯對象都會延遲加載。 特定關聯關系中可通過設置?fetchType?屬性來覆蓋該項的開關狀態。true | falsefalse
aggressiveLazyLoading當開啟時,任何方法的調用都會加載該對象的所有屬性。 否則,每個屬性會按需加載(參考?lazyLoadTriggerMethods)。true | falsefalse?
defaultExecutorType配置默認的執行器。SIMPLE 就是普通的執行器;REUSE 執行器會重用預處理語句(prepared statements); BATCH 執行器將重用語句并執行批量更新。SIMPLE REUSE BATCHSIMPLE
lazyLoadTriggerMeth ods
?
指定哪個對象的方法觸發一次延遲加載。用逗號分隔的方法列表。

equals,clone

hashCode,toString

localCacheScopeMyBatis 利用本地緩存機制(Local Cache)防止循環引用(circular references)和加速重復嵌套查詢。 默認值為 SESSION,這種情況下會緩存一個會話中執行的所有查詢。 若設置值為 STATEMENT,本地會話僅用在語句執行上,對相同 SqlSession 的不同調用將不會共享數據SESSION | STATEMENTSESSION
logImpl指定 MyBatis 所用日志的具體實現,未指定時將自動查找。SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING未設置

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

typeHandlers
用于把Java對象轉換為數據庫的值,或者把數據庫的值轉換成 Java 對象;比放說(String和varchar)
對于一些基礎類型,MyBatis里內置了一些基本的TypeHandler, 都注冊在TypeHandlerRegistry,他們都繼承了抽象類BaseTypeHandler,我們也可以實現自己的TypeHandler

需要實現以下四個抽象方法

使用的時候,需要先在mybatis-config.xml里注冊對應的TypeHandler

<!-- mybatis-config.xml --> <typeHandlers><typeHandler handler="org.mybatis.example.ExampleTypeHandler"/> </typeHandlers>

然后在我們需要使用的字段上指定對應的typeHandler就可以了

#插入 <insert id="insertBlog" parameterType="blog">insert into blog (bid, name, author_id)values (#{bid,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR,typeHandler=com.chenpp.type.MyTypeHandler}, #{authorId,jdbcType=CHAR}) </insert> #查詢結果映射<resultMap id="BaseResultMap" type="blog"><id column="bid" property="bid" jdbcType="INTEGER"/><result column="name" property="name" jdbcType="VARCHAR" typeHandler="com.chenpp.type.MyTypeHandler"/><result column="author_id" property="authorId" jdbcType="INTEGER"/> </resultMap>

objectFactory
ObjectFactory用于創建實體類的實例,當我們把數據庫返回的結果集轉換為實體類的時候,就會使用ObjectFactory通過反射來創建對象,里面定義了4個方法

public interface ObjectFactory {void setProperties(Properties var1);<T> T create(Class<T> var1);<T> T create(Class<T> var1, List<Class<?>> var2, List<Object> var3);<T> boolean isCollection(Class<T> var1); }

ObjectFactory 有一個默認的實現類DefaultObjectFactory,創建對象的方法最終都調用了instantiateClass(),是通過反射來完成實例化的
如果想要修改對象工廠在映射實體類時的行為,就可以創建自己的對象工廠,只需要繼承DefaultObjectFactory然后重寫create()方法就可以了

plugins
插件是MyBatis的一個很強大的機制,跟很多其他的框架一樣,MyBatis預留了插件的接口,讓MyBatis更容易擴展。這個會在后面詳細分析

environmentsenvironment
environments標簽用來管理數據庫的環境,比如我們可以有開發環境、測試環境、生產環境等不同環境的數據庫。可以在不同的環境中使用不同的數據庫。這里面有兩個關鍵的標簽,一個是事務管理器,一個是數據源

transactionManager
如果配置的是JDBC,就會直接使用?JDBC 的提交和回滾設置,它依賴于從數據源得到的連接來管理事務作用域
如果配置成MANAGED,會把事務交給容器來管理,比如JBOSS,Weblogic等。如果直接在本地環境運行程序,配置成MANAGE的話不會有任何事務。

dataSource
dataSource 元素使用標準的 JDBC 數據源接口來配置 JDBC 連接對象的資源。有三種內建的數據源類型(也就是UNPOOLED,POOLED,JNDI)
UNPOOLED– 這個數據源的實現只是每次請求時打開和關閉連接。
POOLED–使用來連接池管理?JDBC 連接對象,復用連接
JNDI?– 這個數據源的實現是為了能在如 EJB 或應用服務器這類容器中使用
在跟Spring集成的時候,事務和數據源都會交給Spring來管理。

mappers
<mappers>標簽配置的是我們的映射器,也就是Mapper.xml的路徑。這里配置的目的是讓MyBatis在啟動的時候去掃描這些映射器,創建映射關系。我們有四種指定Mapper文件的方式:

  • ???使用相對于類路徑的資源引用(resource)
  • ???使用完全限定資源定位符(URL)
  • ? ?使用映射器接口實現類的完全限定類名
  • ???將包內的映射器接口實現全部注冊為映射器(最常用)

Mapper映射配置文件

一共有8個主要標簽

cache – 給定命名空間的緩存配置(是否開啟二級緩存)。
cache-ref – 其他命名空間緩存配置的引用。
resultMap – 用來描述如何從數據庫結果集中來加載對象 ?數據庫結果集和java對象的映射關系
sql – 可被其他語句引用的可重用語句塊。
增刪改查標簽:
insert ,update ,delete ,select?

MyBatis的擴展使用

動態SQL

基于OGNL表達式,幫助我們更方便的拼接SQL

MyBatis的動態標簽主要有四類: if, choose(when,otherwise),trim (where, set),foreach。

if —— 用于做判斷,條件寫在test中

choose (when, otherwise) —— 用于做條件選擇

<select id="findActiveBlogLike"resultType="Blog">SELECT * FROM BLOG WHERE state = ‘ACTIVE’<choose><when test="title != null">AND title like #{title}</when><when test="author != null and author.name != null">AND author_name like #{author.name}</when><otherwise>AND featured = 1</otherwise></choose> </select>

trim, where, set——會幫助我們去掉多余的where,and,逗號之類的符號,使用trim還可以指定獲取去掉前綴/后綴

where?元素只會在至少有一個子元素的條件返回 SQL 子句的情況下才去插入“WHERE”子句。而且,若語句的開頭為“AND”或“OR”,where?元素也會將它們去除。
如果?where?元素沒有按正常套路出牌,我們可以通過自定義 trim 元素來定制?where?元素的功能。比如,和?where?元素等價的自定義 trim 元素為:

<trim prefix="WHERE" prefixOverrides="AND |OR ">... </trim>

foreach —— 適用于需要遍歷集合的時候

<select id="selectPostIn" resultType="domain.blog.Post">SELECT *FROM POST PWHERE ID in<foreach item="item" index="index" collection="list"open="(" separator="," close=")">#{item}</foreach> </select>

批量SQL

使用for each拼接長SQL

缺點:MySQL 的服務端對于接收的數據包有大小限制,max_allowed_packet 默認是4M,需要修改對應的參數配置

使用BatchExecutor進行批操作

在我們的全局配置文件中,可以配置默認的 Executor 的類型。其中有一種BatchExecutor
<setting name="defaultExecutorType" value="BATCH"/>
也可以在創建會話的時候指定執行器類型
SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
BatchExecutor底層是就是調用了JDBC的ps.addBatch()方法(在BatchExecutor調用了StatementHandler的batch(),在里面調用了statement的addBatch()方法)

嵌套(關聯)查詢/ N+1 / 延遲加載

對于一對一的關聯查詢有兩種配置方式

嵌套結果:

<!-- 根據文章查詢作者,一對一查詢的結果,嵌套結果 --><resultMap id="BlogWithAuthorResultMap" type="com.chenpp.domain.associate.BlogAndAuthor"><id column="bid" property="bid" jdbcType="INTEGER"/><result column="name" property="name" jdbcType="VARCHAR"/><!-- 聯合查詢,將author的屬性映射到ResultMap --><association property="author" javaType="com.chenpp.domain.Author"><id column="author_id" property="authorId"/><result column="author_name" property="authorName"/></association></resultMap><!-- 根據文章查詢作者,一對一,嵌套結果,無N+1問題 --><select id="selectBlogWithAuthorResult" resultMap="BlogWithAuthorResultMap" >select b.bid, b.name, b.author_id, a.author_id , a.author_namefrom blog bleft join author aon b.author_id=a.author_idwhere b.bid = #{bid, jdbcType=INTEGER}</select>

?

嵌套查詢

<!-- 另一種聯合查詢(一對一)的實現,但是這種方式有“N+1”的問題 --><resultMap id="BlogWithAuthorQueryMap" type="com.chenpp.domain.associate.BlogAndAuthor"><id column="bid" property="bid" jdbcType="INTEGER"/><result column="name" property="name" jdbcType="VARCHAR"/><association property="author" javaType="com.chenpp.domain.Author"column="author_id" select="selectAuthor"/> <!-- selectAuthor 定義在下面--></resultMap><!-- 根據文章查詢作者,一對一,嵌套查詢,存在N+1問題,可通過開啟延遲加載解決 --><select id="selectBlogWithAuthorQuery" resultMap="BlogWithAuthorQueryMap" >select b.bid, b.name, b.author_id, a.author_id , a.author_namefrom blog bleft join author aon b.author_id=a.author_idwhere b.bid = #{bid, jdbcType=INTEGER}</select><!-- 嵌套查詢 --><select id="selectAuthor" parameterType="int" resultType="com.chenpp.domain.Author">select author_id authorId, author_name authorNamefrom author where author_id = #{authorId}</select>

對于第二種嵌套查詢,因為是分兩次查詢的,當我們查詢了博客信息之后,會再發送一條SQL到數據庫查詢作者信息。如果查詢出N條博客記錄,那么就需要再執行N次作者的SQL查詢 ?這就是所謂的N+1問題
在MyBatis里面可以通過開啟延遲加載的開關來解決這個問題

<!-- 延遲加載的全局開關。當開啟時,所有關聯對象都會延遲加載。默認 false --><setting name="lazyLoadingEnabled" value="true"/><!-- 當開啟時,任何方法的調用都會加載該對象的所有屬性。默認 false,可通過select標簽的 fetchType來覆蓋--><setting name="aggressiveLazyLoading" value="false"/><!-- Mybatis 創建具有延遲加載能力的對象所用到的代理工具,默認JAVASSIST --><setting name="proxyFactory" value="CGLIB" />

簡單來說,lazyLoadingEnabled決定了是否延遲加載。
aggressiveLazyLoading決定了是不是對象的所有方法都會觸發查詢。

邏輯翻頁與物理翻頁

在我們查詢數據庫的操作中,有兩種翻頁方式,一種是邏輯翻頁(假分頁),一種是物理翻頁(真分頁)。邏輯翻頁的原理是把所有數據查出來,在內存中刪選數據。 物理翻頁是真正的翻頁,比如MySQL 使用limit ,Oracle使用rownum 。

邏輯翻頁

MyBatis 里面有一個邏輯分頁對象 RowBounds,里面主要有兩個屬性,offset 和limit(從第幾條開始,查詢多少條).
我們可以在Mapper接口的方法上加上這個參數, 而不需要修改xml里的SQL語句達到邏輯翻頁的效果。

public List<Blog> selectBlogList(RowBounds rowBounds);

物理翻頁

1.直接傳入參數(或者包裝一個page對象),在SQL語句中翻頁。

<select id="selectBlogPage" parameterType="map" resultMap="BaseResultMap">select * from blog limit #{curIndex} , #{pageSize}</select>

2.使用翻頁的插件,比如PageHelper,后面會介紹下MyBatis插件的原理和PageHelper的實現
簡單地來說,就是根據 PageHelper 的參數,改寫我們的 SQL語句

?

?

總結

以上是生活随笔為你收集整理的MyBatis(一)MyBatis介绍和配置详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。