1.spring配置datasource bean的時候,不同的數據庫連接方式有有不同的datasource實現類。
比如采用c3p0數據庫連接池,要用c3p0的datasource實現類 com.mchange.v2.c3p0.ComboPooledDataSource
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass">
<value>${jdbc.driver}
2.sqlsessionFactory的bean是mybatis提供具體實現類的,並向其中個注入datasource bean。
bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="/WEB-INF/cfg/mybatis-config.xml"></property>
</bean>
3.使用前兩步,就在spring中啟動了mybatis,並向ioc容器中注入了spring的sqlsessionfactory bean。spring程序接下來就可以使用Mybatis了。
web程序具體具體使用如下:
配置響應的dao接口實現bean。接口bean的class源還是mybatis提供的mapper類。class="org.mybatis.spring.mapper.MapperFactoryBean"
每個mapper都是dao接口的實現。
<bean id="ProductDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.dao.ProductI"></property>
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
4.MyBatis幾乎淘汰了所有的JDBC編碼和手工設置參數以及結果的檢索。
具體省去:獲得connection,statement,及connection的關閉這種每個connection都調用的重復方法。
5.2.1.1 通過XML創建SqlSessionFactory
通過一個xml文件的配置創建SqlSessionFactory是非常簡單的。推薦你使用一個classpath resource去配置,另外你需要使用流,流中包含一個文件路徑或者URL。MyBatis包含一個工具類,這個工具類中有一個方法可以含有類路徑的資源:
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
這個XML配置文件含有對MyBatis系統的核心設置,包含一個獲得數據連接實例的數據源,同時也含有一個如何處理和控制的事物管理器。關於XML配置文件的細節我們會在文檔后面涉及,這個給出一個簡單的示例:
<?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>
<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配置文件,在上述的例子中需要指出的是,注意XML配置文件的頭部,必須要有XML文檔的驗證,environment體中包含對事物環境配置和連接池。mappers元素是一個映射列表包含sql和映射定義。
2.1.2 不使用XMl構建SqlSessionFactory
如果你喜歡直接用java來配置那是優於XML的,或者創建屬於你自己的配置構造器。MyBatis提供了和XMl配置文件性質相同的配置類。
DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
在這個例子中需要注意的是要添加一個映射類,在映射類中可以使用注解來避免使用XMl。但是,由於Java注解的一些限制和一些MyBatis映射的復雜性,XMl映射還是比較高級的映射。由於這個原因,MyBatis將會自動的去查看存在的xml文件。稍后詳述。
6.SqlSessionFactory的生命周期
一旦創建,SqlSessionFactory應該在你的應用執行范圍內存在。一般很少有理由需要處理它或者重新創建它。SqlSessionFactory不該在程序運行中重建是一種最佳實踐。因此,SqlSessionFactory的最佳范圍應該是應用范圍。實現這個的方式有很多中,最簡單的方式就是單利模式或者靜態模式。
7. SqlSession的生命周期
每個線程都該有自己的SqlSession,每個SqlSession實例不該被共享。因此最好的范圍是請求范圍或者方法范圍。不要把SqlSession定義在一個靜態字段或者實例字段中。不要提升任何范圍去管理SqlSession。比如Servlet框架中的HttpSession,如果你使用任何類型的web框架,一個HTTP請求應該遵循類似的規范。就是說,在接受一個HTTP請求,你可以打開一個SqlSession,然后在返回響應的時候,關閉它。關閉session是非常重要的。你必須要始終確保它在最后被關閉。下面這個是標准的關閉模式:
SqlSession session = sqlSessionFactory.openSession();
try {
// do work
} finally {
session.close();
}
使用這個代碼將確保所有的session在處理完之后都會被關閉。
8.mapper實例
Mappers是一個接口實現類,mapper綁定了你創建的映射語句和接口類。
9.依賴注入框架是線程安全的,交易SqlSession和Mapper和注入到你的bean中你可以不用管理他們的聲明周期。你可以研究一下這些框架。
10.Mybatis強大之處
MyBatis的真正的強大在於映射。這正是奇跡發生的地方。這是他們所有的力量之源,映射的XML文件時簡單的。當然如果你把他們和等效的代碼相比較,你馬上就會發現這里省去了95%的代碼,MyBatis建立了一個遠離你的方式只關注與SQL。
映射文件中有很少的第一類元素:
cache
cache-ref
resultMap
parameterMap
sql
insert
update
delete
select
接下來我們將從他們的語句中討論一下他們的細節:
4.1.1 selcet
select語句是你在MyBatis使用的流行的語句之一,取出數據庫中的數據時非常有價值的一件事。所以大多數數據庫應用中查詢遠遠超過其它加在一起的操作。每一個插入,更行和刪除,可能會對應很多的select.這也是MyBatis建議的原則之一,就是有大量的查詢對應結果集。select是相當簡單的案例。例如:
<select id="selectPerson" parameterType="int" resultType="hashmap">
SELECT * FROM PERSON WHERE ID = #{id}
</select>
選一個人對象,通過一個int類型的參數。返回一個HashMap值。
這里需要注意參數。
#{id}
這個類似於JDBC中的這個意思:
// Similar JDBC code, NOT MyBatis…
String selectPerson = "SELECT * FROM PERSON WHERE ID=?";
PreparedStatement ps = conn.prepareStatement(selectPerson);
ps.setInt(1,id);
當然,還有更多的代碼通過JDBC單獨提取所需的結果並將它們映射到一個對象實例.
這里
<select
id="selectPerson"
parameterType="int"
parameterMap="deprecated"
resultType="hashmap"
resultMap="personResultMap"
flushCache="false"
useCache="true"
timeout="10000"
fetchSize="256"
statementType="PREPARED"
resultSetType="FORWARD_ONLY">
5.mybatis映射文件書寫
1.映射文件的開發如下圖
2,映射文件配置好了之后,還需要在全局配置文件sqlMapConfig.xml中添加映射文件
3,sqlsession會話去執行操作查詢數據庫映射文件,下圖中的錯誤糾正為’%${value}%’
查詢出的是單條記錄使用selectOne,下圖中的錯誤糾正為把“1”改為int類型的1
sqlsession.selectOne(“test.findUserById”, 1);
查詢出的是多條記錄使用selectList
sqlsession.selectList(“test.findUserByName”, “hello”);
5,總結:
四 mybatis開發dao方法
mybatis的配置文件不變
1,先使用原型的開發dao方法
開發接口
2, 開發接口實現
3, 測試代碼
4,總結
五 mybatis利用mapper代理開發dao(重點掌握)
mapper代理開發,就不需要接口的實現類,只需要接口UserMapper.java和映射文件UserMapper.xml就可以了,但是遵循一定的開發規范:
1,在UserMapper.xml文件中namespace等於UserMapper接口地址
2,UserMapper.java接口中的方法名要和UserMapper.xml中的statement的id一致
3,UserMapper.java接口中的方法輸入參數要和UserMapper.xml中的statement的parameterType指定的類型一致
4,UserMapper.java接口中的方法的返回值類型要和UserMapper.xml中的statement的resultType指定的類型一致
測試代碼:
上圖畫線區域:這里沒有實現接口的實現類,而是使用mybatis生成的代理對象來生成UserMappper接口的對象,從而能夠調用其方法
mapper代理開發dao出現的問題總結:
1,代理對象內部調用selectOne或selectList
如果mapper方法返回單個pojo對象(非集合對象),代理對象內部通過selectOne查詢數據庫,也可以使用selectList查詢。
如果mapper方法返回集合對象,代理對象內部通過selectList查詢 數據庫,不能使用selectOne查詢,否則會出錯。
問題是: 編譯期間不會報錯,二者容易寫錯使用。
2,mapper接口方法參數只有一個
根據規范編寫的代理對象的傳入參數只能有一個(mapper.xml文件中的parameterType參數只有一個),不利於系統的擴展
解決:即使mapper接口中只有一個參數,可以使用包裝類型的pojo滿足不同的業務方法需求
mybatis的一些細節剖析:
1,全局配置文件sqlMapConfig.xml中配置內容如下:
-
properties(屬性)
注意:mybatis將按照下面的順序來加載屬性:
(1)在properties元素體內定義的屬性首先被讀取。(可以在此屬性中加入jdbc的配置文件db.properties),在sqlMapConfig.xml中就不需要對數據庫連接參數進行硬編碼了。 -
settings全局參數設置
mybatis框架運行時可以調整一些運行參數,會影響mybatis運行行為,所以建議不要隨便修改
比如:二級緩存,開啟延時加載。。。 - typeAliases(別名) 重點掌握
<typeAliases> <!--針對單個別名定義 type:類型的路徑 alias:別名 --> <typeAlias type="com.jary.mybatis.po.User" alias="user" /> <!--還可以進行批量別名定義 指定包名,mybatis自動掃描包中的po類 --> <package name="com.jary.mybatis.po" /> </typeAliases>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
上面的別名定義后,在mapper.xml中就可以這樣使用了
user代替了輸出結果類型com.jary.mybatis.po.User。
4.映射文件(mapper)
通過resource加載單個的映射文件
<mapper resource="mapper/UserMapper.xml" />
- 1
通過mapper接口加載單個mapper,要遵循一定的規范:
(1)前提是使用mapper代理開發(已經有4個規范)
(2)需要將mapper接口類名和mapper.xml映射文件名稱保持一致,且在同一目錄下
<mapper class="com.jary.mybatis.mapper.UserMapper" />
- 1
通過批量加載mapper(推薦使用):實現條件是
要滿足mapper接口加載映射文件和使用mapper代理開發同時滿足
mybatis的一些細節剖析結束
mybatis的核心輸入映射和輸出映射開始:
輸入映射
通過parameterType指定輸入參數類型,類型可以是簡單類型、hashmap、pojo的包裝類型
1,傳遞pojo的包裝對象
(1)需求
完成用戶信息的綜合查詢,需要傳入查詢條件復雜(可能包括用戶信息,商品信息,商品訂單等),這樣靠一個parameterType只能傳入一個輸入參數,所有需要pojo的包裝類型來實現
(2)定義包裝類型pojo
針對上面的需求,在包裝類型的pojo中把這些復雜的查詢條件包裝進去,定義包裝類UserQueryVo,把需要查詢的條件全部定義在里面
上圖中標注的用戶查詢條件使用的是User的擴展類(因為User類一般是由逆向工程自動生成的,不要進行修改,所有使用的擴展類來實現)
映射文件UserMapper.xml配置
UserMapper.java接口文件的配置
上圖中,把包裝類作為參數傳入,返回值是一個用戶列表所以用list集合接收
測試代碼如下圖:
輸出映射
1,resultType
使用resultType進行輸出映射時,只有查詢輸出結果列名和pojo中的屬性名一致才可以,映射成功
如果查詢出來的列名和pojo中的屬性名沒有一個一致的,就不會創建pojo對象
如果查詢出來的列名和pojo中的屬性名有一個一致,就會創建pojo對象
輸出pojo對象和pojo列表
不管是輸出的pojo單個對象還是一個列表(list中包含pojo),在mapper.xml中resultType指定的類型是一樣的
在mapper.java指定的方法返回值類型不一樣:
(1)輸出單個pojo對象,方法返回值是個單個對象類型
(2)輸出pojo對象list,方法返回值就是list對象類型
在動態代理對象中,是根據mapper方法的返回值類型來確定是調用selectOne(返回單個對象)還是selectList(返回集合對象)
2,resultMap
使用resultMap進行映射時,查詢結果列名和pojo的屬性名不一致時,resultMap會對列名和pojo屬性名進行映射,保證其成功映射
使用resultMap需要這二步:
(1)定義resultMap
(2)使用resultMap作為statement的輸出映射類型
mybatis的核心輸入映射和輸出映射結束:
mybatis的動態sql和sql片段開始:
動態sql
mybatis核心就是對sql語句進行靈活操作,通過表達式進行判斷,對sql進行靈活拼接和組裝。
需求:用戶信息查詢的綜合信息需要使用動態sql
對查詢條件進行判斷,如果出入參數不為空,才進行拼接
測試代碼需要注意的是如下圖:
如果不設置某個值,條件將不拼接在sql中
sql片段
需求:將上面的動態sql(重復的sql語句)抽取出來做成一個片段,方便其他statement語句重復使用sql片段
使用sql片段
使用foreach標簽遍歷
給sql傳入數組或者集合時,mybatis使用foreach解析
需求:在用戶信息的綜合查詢中增加多個id傳入
sql語句如下:
select * from user where id=1 or id=3 or id=5
也可以使用select * from user where id in(1,3,5)
mybatis的動態sql和sql片段結束
mybatis高級映射開始:
一、 高級映射一對一查詢(使用到assocition標簽實現關聯對象的一對一查詢映射),分別使用resultType和resultMap,並且比較二者的區別
還有一點就是,resultType查詢關聯列表結果列如果和pojo屬性名不一致,需要自己創建擴展類(繼承包括結果集列名多的pojo對象,這樣可以少寫一點屬性名)。resultMap則不需要創建擴展類,而是把關聯信息的對象注入,從而實現結果集列名和pojo屬性名保持一致。
二、高級映射一對多查詢(使用collection標簽來實現關聯對象的一對多查詢映射),一對多,就是關聯的對象查詢結果是一個List集合
開發步驟:
(1)首先寫sql語句
需求:查詢訂單及訂單明細信息(一個訂單包含多個訂單明細,所以一對多)
主表:訂單表
關聯表:訂單明細表
經過之前一對一查詢(用戶的訂單)的分析,我們只需要在此基礎上關聯訂單明細表即可。
(2)pojo類(resultType時用到擴展類,這里我們使用resultMap不需要包裝類)
(3)mapper.xml(這里我們使用了resultMap的繼承,不需要重新關聯訂單表和用戶表,通過繼承之前的一對一(用戶查詢訂單)所寫的二個表,可以減少大量的重復代碼。同時使用了collection集合標簽將關聯查詢出的多條記錄映射到List集合中)
(4)mapper.java
一對多查詢總結:
mybatis使用resultMap的collection(resultType沒有此標簽)對關聯查詢的多條記錄映射到一個list集合中。
使用resultType通過雙重循環遍歷可以實現,去除重復記錄,將訂單明細映射在orderdetail中(了解)
多對多查詢實例和上邊類似。主要是搞清楚各個表之間的對應關系,訂單的collection中嵌套訂單明細的collection,而訂單明細的collection中嵌套商品信息。
mybatis高級映射結束
mybatis的延遲加載和緩存技術開始
mybatis一級緩存
mybatis的二級緩存
mybatis默認是沒有開啟二級緩存的。
開啟二級緩存需要在mybatis的全局配置文件sqlMapConfig.xml中加入
除了開啟二級緩存開關外,還需要在各自的mapper.xml中開啟二級緩存。
原理圖:
如上圖:sqlsession1去查詢id為1的用戶信息,查詢到用戶信息就會查詢數據存放在二級緩存區域(hashmap)中
sqlsession2去查詢id為1的用戶信息,首先去緩存中查找是否存在數據,如果存在就直接從二級緩存中取出數據。
二級緩存和一級緩存的區別:二級緩存的范圍更大,多個sqlsession
可以共享usermapper的二級緩存。
二級緩存是根據mapper的namespace來划分的,相同namaspace下的mapper共享二級緩存,反之
如果sqlsession3去執行相同mapper下sql,並執行commit()操作,則清空該命名空間下的二級緩存
二級緩存的測試代碼:
上面塗黃部分要特別注意,sqlsession關閉時才可以把數據寫到二級緩存區域中,如果本namespace下的sqlsession執行了commit()操作,二級緩存就會清空
禁用二級緩存
也可以禁用單個查詢的二級緩存,這樣要保證每次查詢的都是最新數據。
刷新二級緩存(就是清空緩存,切記)
總結:一般情況下,執行commit()操作之后,都要刷新緩存,因此flushCache都設為true,來避免數據的臟讀。
mybatis cache的參數設置
flushInterval(刷新間隔),可以為任意整數,單位為毫秒值,這個比較有用。
mybatis和第三方分布式緩存框架整合(ehcache,redis,memcache)
mybatis在緩存方面還是比較弱,特別是分布式緩存不支持
我們的系統為了提高系統並發,性能,一般對系統進行分布式部署(集群部署方式)
整合方法
mybatis提供了一個cache接口,如果要實現自己的緩存邏輯,實現cache接口即可
mybatis和ehcache整合,mybatis和ehcache整合包中提供了一個cache接口的實現類。
二級緩存的應用場景(實際開發中用 刷新間隔)
二級緩存額局限性
細粒度緩存,就是修改一個商品信息(即執行commit()方法),只修改緩存中這一個商品的信息,其余的信息不清空。
mybatis的延遲加載和緩存技術結束
mybatis和spring的整合(重點掌握)開始
1、整合的思路:
(1)首先需要spring通過單例方式管理sqlSessionFactory
(2)spring和mybatis整合生成代理對象,使用SqlSessionFactory創建sqlSession會話(此步是由spring和mybatis整合自動完成)
(3)持久層的mapper,dao都需要由spring來管理
2、環境的搭建
上面的sqlmap目錄下的User.xml是為了原始dao開發使用的。還要加載spring,mybatis,mybatis-srping等jar包。
3、在spring的配置文件中配置sqlSessionFactory和數據源
sqlSessionFactory在mybatis和spring的整合包下
上圖中:使用C3P0配置數據庫連接池,屬性參數名要按照規定寫,不能自己定義,否則會報錯,而使用dbcp就可以自定義參數名,這點注意。
在加載配置文件時,都要加上類路徑名classpath
在使用原始dao開發時,屬性name值要與UserDaoImpl類中變量名一致(特別是大小寫)
4、*原始Dao的開發(和spring整合后)*
4.1 User.xml(也稱mapper.xml更准確)
和spring整合后,需要使用spring來管理mapper,spring配置文件為applicationContext.xml
還有mybatis的配置文件來加載User.xml
4.2 UserDAO
基本上不用改變
4.3 UserDaoImpl(重點在Dao的實現類上)
上圖中的代碼最重要的就是繼承了SqlSessionDaoSupport通過this.getSqlSession()來得到SqlSession會話
這里也不需要寫sqlSession的事務提交(更新操作不用寫)和sqlSession關閉
4.4 測試代碼
5、使用mapper代理來開發 (mybatis和spring整合后)
和利用原始dao開發差不多,只是不需要dao接口的實現類
而是根據一個規范來實現dao接口生成代理對象
5.1規范:
(1)mapper.xml中的namespace命名空間等於mapper.java的全路徑名
(2)mapper.xml和mapper.java應在同一個目錄下
(3)mapper.xml中的statement語句的輸入參數paramType類型應與mapper.java中方法中傳遞的參數類型一致
(4)mapper.xml中的statement語句的輸出參數resultType類型應與mapper.java中方法返回值類型一致
5.2 讓spring來管理mapper,在配置文件中
重點在這里,使用mybatis和spring的整合包中MapperFactoryBean來實現mapper接口生成代理對象
屬性值有mapperInterface和sqlSessionFactory
總結:此方法存在一個大問題,需要針對每個mapper進行配置,太麻煩
終極解決方案: 通過mapper批量掃描,從mapper包中掃描出mapper接口,自動創建代理對象並且在spring容器中注冊
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
- 1
上面代碼,不能使用ref而是使用value,剛開始用錯了。
開發中推薦使用自動掃描,
mybatis和spring的整合(重點掌握)結束
mybatis的逆向工程(了解會用就行)
generator.xml的配置,這里要記住,上圖中最下邊table后面的一長串值等於false的屬性,是為了不生成其他與我們無關的example等代碼
下面需要mybatis-generator-core-1.3.2.jar和generator.xml文件在同於目錄下,並且建立src目錄接收生成的文件
生成后的如下圖
沒有了example的無用類了,比較干凈,推薦使用