摘要:的實(shí)例不能共享使用,它也是線(xiàn)程不安全的。因此最佳的范圍是請(qǐng)求或方法范圍定義局部變量使用。在中就不需要直接對(duì)數(shù)據(jù)庫(kù)的連接參數(shù)進(jìn)行硬編碼了。
轉(zhuǎn)載請(qǐng)務(wù)必注明出處,原創(chuàng)不易!
相關(guān)文章:通過(guò)項(xiàng)目逐步深入了解Mybatis<一> 本項(xiàng)目全部代碼地址:Github-Mybatis Mybatis 解決 jdbc 編程的問(wèn)題1、 數(shù)據(jù)庫(kù)鏈接創(chuàng)建、釋放頻繁造成系統(tǒng)資源浪費(fèi)從而影響系統(tǒng)性能,如果使用數(shù)據(jù)庫(kù)鏈接池可解決此問(wèn)題。
解決:在SqlMapConfig.xml中配置數(shù)據(jù)鏈接池,使用連接池管理數(shù)據(jù)庫(kù)鏈接。
2、 Sql語(yǔ)句寫(xiě)在代碼中造成代碼不易維護(hù),實(shí)際應(yīng)用sql變化的可能較大,sql變動(dòng)需要改變java代碼。
解決:將Sql語(yǔ)句配置在XXXXmapper.xml文件中與java代碼分離。
3、 向sql語(yǔ)句傳參數(shù)麻煩,因?yàn)閟ql語(yǔ)句的where條件不一定,可能多也可能少,占位符需要和參數(shù)一一對(duì)應(yīng)。
解決:Mybatis自動(dòng)將java對(duì)象映射至sql語(yǔ)句,通過(guò)statement中的parameterType定義輸入?yún)?shù)的類(lèi)型。
4、 對(duì)結(jié)果集解析麻煩,sql變化導(dǎo)致解析代碼變化,且解析前需要遍歷,如果能將數(shù)據(jù)庫(kù)記錄封裝成pojo對(duì)象解析比較方便。
解決:Mybatis自動(dòng)將sql執(zhí)行結(jié)果映射至java對(duì)象,通過(guò)statement中的resultType定義輸出結(jié)果的類(lèi)型。
Mybatis 與 Hibernate 不同Mybatis和hibernate不同,它不完全是一個(gè)ORM框架,因?yàn)镸yBatis需要程序員自己編寫(xiě)Sql語(yǔ)句,不過(guò)mybatis可以通過(guò)XML或注解方式靈活配置要運(yùn)行的sql語(yǔ)句,并將java對(duì)象和sql語(yǔ)句映射生成最終執(zhí)行的sql,最后將sql執(zhí)行的結(jié)果再映射生成java對(duì)象。
Mybatis學(xué)習(xí)門(mén)檻低,簡(jiǎn)單易學(xué),程序員直接編寫(xiě)原生態(tài)sql,可嚴(yán)格控制sql執(zhí)行性能,靈活度高,非常適合對(duì)關(guān)系數(shù)據(jù)模型要求不高的軟件開(kāi)發(fā),例如互聯(lián)網(wǎng)軟件、企業(yè)運(yùn)營(yíng)類(lèi)軟件等,因?yàn)檫@類(lèi)軟件需求變化頻繁,一但需求變化要求成果輸出迅速。但是靈活的前提是mybatis無(wú)法做到數(shù)據(jù)庫(kù)無(wú)關(guān)性,如果需要實(shí)現(xiàn)支持多種數(shù)據(jù)庫(kù)的軟件則需要自定義多套sql映射文件,工作量大。
Hibernate對(duì)象/關(guān)系映射能力強(qiáng),數(shù)據(jù)庫(kù)無(wú)關(guān)性好,對(duì)于關(guān)系模型要求高的軟件(例如需求固定的定制化軟件)如果用hibernate開(kāi)發(fā)可以節(jié)省很多代碼,提高效率。但是Hibernate的學(xué)習(xí)門(mén)檻高,要精通門(mén)檻更高,而且怎么設(shè)計(jì)O/R映射,在性能和對(duì)象模型之間如何權(quán)衡,以及怎樣用好Hibernate需要具有很強(qiáng)的經(jīng)驗(yàn)和能力才行。
總之,按照用戶(hù)的需求在有限的資源環(huán)境下只要能做出維護(hù)性、擴(kuò)展性良好的軟件架構(gòu)都是好架構(gòu),所以框架只有適合才是最好。
Mybatis 開(kāi)發(fā) dao 兩種方法原始 dao 開(kāi)發(fā)方法(程序需要編寫(xiě) dao 接口和 dao 實(shí)現(xiàn)類(lèi))(掌握)
Mybatis 的 mapper 接口(相當(dāng)于 dao 接口)代理開(kāi)發(fā)方法(掌握)
需求將下邊的功能實(shí)現(xiàn)Dao:
根據(jù)用戶(hù)id查詢(xún)一個(gè)用戶(hù)信息
根據(jù)用戶(hù)名稱(chēng)模糊查詢(xún)用戶(hù)信息列表
添加用戶(hù)信息
Mybatis 配置文件 SqlMapConfig.xml
Sqlsession 的使用范圍SqlSession 中封裝了對(duì)數(shù)據(jù)庫(kù)的操作,如:查詢(xún)、插入、更新、刪除等。
通過(guò) SqlSessionFactory 創(chuàng)建 SqlSession,而 SqlSessionFactory 是通過(guò) SqlSessionFactoryBuilder 進(jìn)行創(chuàng)建。
1、SqlSessionFactoryBuilderSqlSessionFactoryBuilder 用于創(chuàng)建 SqlSessionFacoty,SqlSessionFacoty 一旦創(chuàng)建完成就不需要SqlSessionFactoryBuilder 了,因?yàn)?SqlSession 是通過(guò) SqlSessionFactory 生產(chǎn),所以可以將SqlSessionFactoryBuilder 當(dāng)成一個(gè)工具類(lèi)使用,最佳使用范圍是方法范圍即方法體內(nèi)局部變量。
2、SqlSessionFactorySqlSessionFactory 是一個(gè)接口,接口中定義了 openSession 的不同重載方法,SqlSessionFactory 的最佳使用范圍是整個(gè)應(yīng)用運(yùn)行期間,一旦創(chuàng)建后可以重復(fù)使用,通常以單例模式管理 SqlSessionFactory。
3、SqlSessionSqlSession 是一個(gè)面向用戶(hù)的接口, sqlSession 中定義了數(shù)據(jù)庫(kù)操作,默認(rèn)使用 DefaultSqlSession 實(shí)現(xiàn)類(lèi)。
執(zhí)行過(guò)程如下:
1)、 加載數(shù)據(jù)源等配置信息
Environment environment = configuration.getEnvironment();
2)、 創(chuàng)建數(shù)據(jù)庫(kù)鏈接
3)、 創(chuàng)建事務(wù)對(duì)象
4)、 創(chuàng)建Executor,SqlSession 所有操作都是通過(guò) Executor 完成,mybatis 源碼如下:
if (ExecutorType.BATCH == executorType) { executor = newBatchExecutor(this, transaction); } elseif (ExecutorType.REUSE == executorType) { executor = new ReuseExecutor(this, transaction); } else { executor = new SimpleExecutor(this, transaction); } if (cacheEnabled) { executor = new CachingExecutor(executor, autoCommit); }
5)、 SqlSession的實(shí)現(xiàn)類(lèi)即 DefaultSqlSession,此對(duì)象中對(duì)操作數(shù)據(jù)庫(kù)實(shí)質(zhì)上用的是 Executor
結(jié)論:每個(gè)線(xiàn)程都應(yīng)該有它自己的SqlSession實(shí)例。SqlSession的實(shí)例不能共享使用,它也是線(xiàn)程不安全的。因此最佳的范圍是請(qǐng)求或方法范圍(定義局部變量使用)。絕對(duì)不能將SqlSession實(shí)例的引用放在一個(gè)類(lèi)的靜態(tài)字段或?qū)嵗侄沃小? 打開(kāi)一個(gè)SqlSession;使用完畢就要關(guān)閉它。通常把這個(gè)關(guān)閉操作放到 finally 塊中以確保每次都能執(zhí)行關(guān)閉。如下:
SqlSession session = sqlSessionFactory.openSession(); try { // do work } finally { session.close(); }原始 Dao 開(kāi)發(fā)方法 思路:
需要程序員編寫(xiě) Dao 接口和 Dao 實(shí)現(xiàn)類(lèi);
需要在 Dao 實(shí)現(xiàn)類(lèi)中注入 SqlsessionFactory ,在方法體內(nèi)通過(guò) SqlsessionFactory 創(chuàng)建 Sqlsession。
Dao接口public interface UserDao //dao接口,用戶(hù)管理 { //根據(jù)id查詢(xún)用戶(hù)信息 public User findUserById(int id) throws Exception; //添加用戶(hù)信息 public void addUser(User user) throws Exception; //刪除用戶(hù)信息 public void deleteUser(int id) throws Exception; }Dao 實(shí)現(xiàn)類(lèi)
public class UserDaoImpl implements UserDao //dao接口實(shí)現(xiàn)類(lèi) { //需要在 Dao 實(shí)現(xiàn)類(lèi)中注入 SqlsessionFactory //這里通過(guò)構(gòu)造方法注入 private SqlSessionFactory sqlSessionFactory; public UserDaoImpl(SqlSessionFactory sqlSessionFactory) { this.sqlSessionFactory = sqlSessionFactory; } @Override public User findUserById(int id) throws Exception { //在方法體內(nèi)通過(guò) SqlsessionFactory 創(chuàng)建 Sqlsession SqlSession sqlSession = sqlSessionFactory.openSession(); User user = sqlSession.selectOne("test.findUserById", id); sqlSession.close(); return user; } @Override public void insertUser(User user) throws Exception { //在方法體內(nèi)通過(guò) SqlsessionFactory 創(chuàng)建 Sqlsession SqlSession sqlSession = sqlSessionFactory.openSession(); //執(zhí)行插入的操作 sqlSession.insert("test.insetrUser", user); //提交事務(wù) sqlSession.commit(); //釋放資源 sqlSession.close(); } @Override public void deleteUser(int id) throws Exception { //在方法體內(nèi)通過(guò) SqlsessionFactory 創(chuàng)建 Sqlsession SqlSession sqlSession = sqlSessionFactory.openSession(); sqlSession.delete("test.deleteUserById", id); //提交事務(wù) sqlSession.commit(); sqlSession.close(); } }測(cè)試
public class UserDaoImplTest { private SqlSessionFactory sqlSessionFactory; //此方法是在 testFindUserById 方法之前執(zhí)行的 @Before public void setup() throws Exception { //創(chuàng)建sqlSessionFactory //Mybatis 配置文件 String resource = "SqlMapConfig.xml"; //得到配置文件流 InputStream inputStream = Resources.getResourceAsStream(resource); //創(chuàng)建會(huì)話(huà)工廠(chǎng),傳入Mybatis的配置文件信息 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test public void testFindUserById() throws Exception { //創(chuàng)建UserDao的對(duì)象 UserDao userDao = new UserDaoImpl(sqlSessionFactory); //調(diào)用UserDao方法 User user = userDao.findUserById(1); System.out.println(user); } }
通過(guò)id查詢(xún)用戶(hù)信息測(cè)試結(jié)果如下:(其他的可以自己在寫(xiě)測(cè)試代碼,原理類(lèi)似)
問(wèn)題原始Dao開(kāi)發(fā)中存在以下問(wèn)題:
Dao方法體存在重復(fù)代碼:通過(guò) SqlSessionFactory 創(chuàng)建 SqlSession,調(diào)用 SqlSession 的數(shù)據(jù)庫(kù)操作方法
調(diào)用 sqlSession 的數(shù)據(jù)庫(kù)操作方法需要指定 statement 的i d,這里存在硬編碼,不得于開(kāi)發(fā)維護(hù)。
調(diào)用 sqlSession 的數(shù)據(jù)庫(kù)操作方法時(shí)傳入的變量,由于 sqlsession 方法使用泛型,即使變量類(lèi)型傳入錯(cuò)誤,在編譯階段也不報(bào)錯(cuò),不利于程序員開(kāi)發(fā)。
Mybatis 的 mapper 接口 思路程序員需要編寫(xiě) mapper.xml 映射文件
只需要程序員編寫(xiě)Mapper接口(相當(dāng)于Dao接口),需遵循一些開(kāi)發(fā)規(guī)范,mybatis 可以自動(dòng)生成 mapper 接口類(lèi)代理對(duì)象。
開(kāi)發(fā)規(guī)范:
在 mapper.xml 中 namespace 等于 mapper 接口地址
在 xxxmapper.java 接口中的方法名要與 xxxMapper.xml 中 statement 的 id 一致。
在 xxxmapper.java 接口中的輸入?yún)?shù)類(lèi)型要與 xxxMapper.xml 中 statement 的 parameterType 指定的參數(shù)類(lèi)型一致。
在 xxxmapper.java 接口中的返回值類(lèi)型要與 xxxMapper.xml 中 statement 的 resultType 指定的類(lèi)型一致。
UserMapper.java
//根據(jù)id查詢(xún)用戶(hù)信息 public User findUserById(int id) throws Exception;
UserMapper.xml
總結(jié):以上的開(kāi)發(fā)規(guī)范主要是對(duì)下邊的代碼進(jìn)行統(tǒng)一的生成:
User user = sqlSession.selectOne("test.findUserById", id); sqlSession.insert("test.insetrUser", user); sqlSession.delete("test.deleteUserById", id); List測(cè)試list = sqlSession.selectList("test.findUserByName", username);
測(cè)試之前記得在 SqlMapConfig.xml 文件中添加加載映射文件 UserMapper.xml:
測(cè)試代碼:
public class UserMapperTest { private SqlSessionFactory sqlSessionFactory; //此方法是在 testFindUserById 方法之前執(zhí)行的 @Before public void setup() throws Exception { //創(chuàng)建sqlSessionFactory //Mybatis 配置文件 String resource = "SqlMapConfig.xml"; //得到配置文件流 InputStream inputStream = Resources.getResourceAsStream(resource); //創(chuàng)建會(huì)話(huà)工廠(chǎng),傳入Mybatis的配置文件信息 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test public void testFindUserById() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); //創(chuàng)建usermapper對(duì)象,mybatis自動(dòng)生成代理對(duì)象 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //調(diào)用UserMapper的方法 User user = userMapper.findUserById(1); System.out.println(user); } }
通過(guò)id查詢(xún)用戶(hù)信息測(cè)試結(jié)果如下:(其他的請(qǐng)自己根據(jù)上下文寫(xiě)測(cè)試代碼,或者去看我 Github-Mybatis學(xué)習(xí)筆記 上看我這個(gè)項(xiàng)目的全部代碼)
通過(guò)姓名查詢(xún)用戶(hù)信息:
代理對(duì)象內(nèi)部調(diào)用 selectOne 或者 selectList如果 mapper 方法返回單個(gè) pojo 對(duì)象(非集合對(duì)象),代理對(duì)象內(nèi)部通過(guò) selectOne 查詢(xún)數(shù)據(jù)庫(kù)
如果 mapper 方法返回集合對(duì)象,代理對(duì)象內(nèi)部通過(guò) selectList 查詢(xún)數(shù)據(jù)庫(kù)
mapper接口方法參數(shù)只能有一個(gè)是否影響系統(tǒng)開(kāi)發(fā)SqlMapConfig.xml 文件mapper 接口方法參數(shù)只能有一個(gè),系統(tǒng)是否不利于維護(hù)?
系統(tǒng)框架中,dao層的代碼是被業(yè)務(wù)層公用的。
即使 mapper 接口只有一個(gè)參數(shù),可以使用包裝類(lèi)型的 pojo 滿(mǎn)足不同的業(yè)務(wù)方法的需求。
注意:持久層方法的參數(shù)可以包裝類(lèi)型、map.... ,service方法中不建議使用包裝類(lèi)型。(不利于業(yè)務(wù)層的可擴(kuò)展性)
Mybatis 的全局配置變量,配置內(nèi)容和順序如下:
properties(屬性)
settings(全局配置參數(shù))
typeAliases(類(lèi)型別名)
typeHandlers(類(lèi)型處理器)
objectFactory(對(duì)象工廠(chǎng))
plugins(插件)
environments(環(huán)境集合屬性對(duì)象)
? environment(環(huán)境子屬性對(duì)象)
? transactionManager(事務(wù)管理)
? dataSource(數(shù)據(jù)源)
mappers(映射器)
properties 屬性需求:將數(shù)據(jù)庫(kù)連接參數(shù)多帶帶配置在 db.properties 中,只需要在 SqlMapConfig.xml 中加載該配置文件 db.properties 的屬性值。在 SqlMapConfig.xml 中就不需要直接對(duì)數(shù)據(jù)庫(kù)的連接參數(shù)進(jìn)行硬編碼了。方便以后對(duì)參數(shù)進(jìn)行統(tǒng)一的管理,其他的xml文件可以引用該 db.properties 。
db.properties
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis_test?characterEncoding=utf-8 jdbc.username=root jdbc.password=root
那么 SqlMapConfig.xml 中的配置變成如下:
配置完成后我們測(cè)試一下是否能夠和剛才一樣的能夠成功呢?那么我就先在db.properties中把數(shù)據(jù)庫(kù)密碼故意改錯(cuò),看是否是正確的?不出意外的話(huà)是會(huì)報(bào)錯(cuò)的。
注意: MyBatis 將按照下面的順序來(lái)加載屬性:
在 properties 元素體內(nèi)定義的屬性首先被讀取。
然后會(huì)讀取 properties 元素中 resource 或 url 加載的屬性,它會(huì)覆蓋已讀取的同名屬性。
最后讀取 parameterType 傳遞的屬性,它會(huì)覆蓋已讀取的同名屬性。
因此,通過(guò)parameterType傳遞的屬性具有最高優(yōu)先級(jí),resource或 url 加載的屬性次之,最低優(yōu)先級(jí)的是 properties 元素體內(nèi)定義的屬性。
建議:
不要在 properties 元素體內(nèi)添加任何屬性值,只將屬性值定義在 db.properties 文件之中。
在 db.properties 文件之中定義的屬性名要有一定的特殊性。如 xxx.xxx.xxx
settings(全局配置參數(shù))Mybatis 框架在運(yùn)行時(shí)可以調(diào)整一些運(yùn)行參數(shù)
比如:開(kāi)啟二級(jí)緩存、開(kāi)啟延遲加載。。。
typeAliases(類(lèi)型別名)需求:
在mapper.xml中,定義很多的statement,statement需要parameterType指定輸入?yún)?shù)的類(lèi)型、需要resultType指定輸出結(jié)果的映射類(lèi)型。
如果在指定類(lèi)型時(shí)輸入類(lèi)型全路徑,不方便進(jìn)行開(kāi)發(fā),可以針對(duì)parameterType或resultType指定的類(lèi)型定義一些別名,在mapper.xml中通過(guò)別名定義,方便開(kāi)發(fā)。
Mybatis支持的別名:
別名 | 映射的類(lèi)型 |
---|---|
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
自定義別名:
在 SqlMapConfig.xml 中配置:(設(shè)置別名)
在 UserMapper.xml 中引用別名:( resultType 為 user )
測(cè)試結(jié)果:
typeHandlers(類(lèi)型處理器)mybatis中通過(guò)typeHandlers完成jdbc類(lèi)型和java類(lèi)型的轉(zhuǎn)換。
通常情況下,mybatis提供的類(lèi)型處理器滿(mǎn)足日常需要,不需要自定義.
mybatis支持類(lèi)型處理器:
類(lèi)型處理器 | Java類(lèi)型 | JDBC類(lèi)型 |
---|---|---|
BooleanTypeHandler | Boolean,boolean | 任何兼容的布爾值 |
ByteTypeHandler | Byte,byte | 任何兼容的數(shù)字或字節(jié)類(lèi)型 |
ShortTypeHandler | Short,short | 任何兼容的數(shù)字或短整型 |
IntegerTypeHandler | Integer,int | 任何兼容的數(shù)字和整型 |
LongTypeHandler | Long,long | 任何兼容的數(shù)字或長(zhǎng)整型 |
FloatTypeHandler | Float,float | 任何兼容的數(shù)字或單精度浮點(diǎn)型 |
DoubleTypeHandler | Double,double | 任何兼容的數(shù)字或雙精度浮點(diǎn)型 |
BigDecimalTypeHandler | BigDecimal | 任何兼容的數(shù)字或十進(jìn)制小數(shù)類(lèi)型 |
StringTypeHandler | String | CHAR和VARCHAR類(lèi)型 |
ClobTypeHandler | String | CLOB和LONGVARCHAR類(lèi)型 |
NStringTypeHandler | String | NVARCHAR和NCHAR類(lèi)型 |
NClobTypeHandler | String | NCLOB類(lèi)型 |
ByteArrayTypeHandler | byte[] | 任何兼容的字節(jié)流類(lèi)型 |
BlobTypeHandler | byte[] | BLOB和LONGVARBINARY類(lèi)型 |
DateTypeHandler | Date(java.util) | TIMESTAMP類(lèi)型 |
DateOnlyTypeHandler | Date(java.util) | DATE類(lèi)型 |
TimeOnlyTypeHandler | Date(java.util) | TIME類(lèi)型 |
SqlTimestampTypeHandler | Timestamp(java.sql) | TIMESTAMP類(lèi)型 |
SqlDateTypeHandler | Date(java.sql) | DATE類(lèi)型 |
SqlTimeTypeHandler | Time(java.sql) | TIME類(lèi)型 |
ObjectTypeHandler | 任意 | 其他或未指定類(lèi)型 |
EnumTypeHandler | Enumeration類(lèi)型 | VARCHAR-任何兼容的字符串類(lèi)型,作為代碼存儲(chǔ)(而不是索引)。 |
使用相對(duì)于類(lèi)路徑的資源,如:
使用完全限定路徑
如:
使用 mapper 接口類(lèi)路徑
如:
注意:此種方法要求 mapper 接口名稱(chēng)和 mapper 映射文件名稱(chēng)相同,且放在同一個(gè)目錄中。
注冊(cè)指定包下的所有mapper接口
如:
注意:此種方法要求 mapper 接口名稱(chēng)和 mapper 映射文件名稱(chēng)相同,且放在同一個(gè)目錄中。
Mapper.xml映射文件中定義了操作數(shù)據(jù)庫(kù)的sql,每個(gè)sql是一個(gè)statement,映射文件是mybatis的核心。
輸入映射通過(guò) parameterType 指定輸入?yún)?shù)的類(lèi)型,類(lèi)型可以是簡(jiǎn)單類(lèi)型、hashmap、pojo的包裝類(lèi)型。
傳遞 pojo 包裝對(duì)象 (重點(diǎn))
開(kāi)發(fā)中通過(guò)pojo傳遞查詢(xún)條件 ,查詢(xún)條件是綜合的查詢(xún)條件,不僅包括用戶(hù)查詢(xún)條件還包括其它的查詢(xún)條件(比如將用戶(hù)購(gòu)買(mǎi)商品信息也作為查詢(xún)條件),這時(shí)可以使用包裝對(duì)象傳遞輸入?yún)?shù)。
定義包裝對(duì)象
定義包裝對(duì)象將查詢(xún)條件(pojo)以類(lèi)組合的方式包裝起來(lái)。
UserQueryVo.java
public class UserQueryVo //用戶(hù)包裝類(lèi)型 { //在這里包裝所需要的查詢(xún)條件 //用戶(hù)查詢(xún)條件 private UserCustom userCustom; public UserCustom getUserCustom() { return userCustom; } public void setUserCustom(UserCustom userCustom) { this.userCustom = userCustom; } //還可以包裝其他的查詢(xún)條件,比如訂單、商品 }
UserCustomer.java
public class UserCustom extends User //用戶(hù)的擴(kuò)展類(lèi) { //可以擴(kuò)展用戶(hù)的信息 }
UserMapper.xml 文件
UserMapper.java
//用戶(hù)信息綜合查詢(xún) public ListfindUserList(UserQueryVo userQueryVo) throws Exception;
測(cè)試代碼
//測(cè)試用戶(hù)信息綜合查詢(xún) @Test public void testFindUserList() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); //創(chuàng)建usermapper對(duì)象,mybatis自動(dòng)生成代理對(duì)象 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //創(chuàng)建包裝對(duì)象,設(shè)置查詢(xún)條件 UserQueryVo userQueryVo = new UserQueryVo(); UserCustom userCustom = new UserCustom(); userCustom.setSex("男"); userCustom.setUsername("張小明"); userQueryVo.setUserCustom(userCustom); //調(diào)用UserMapper的方法 Listlist = userMapper.findUserList(userQueryVo); System.out.println(list); }
測(cè)試結(jié)果
輸出映射resultType
輸出簡(jiǎn)單類(lèi)型使用 resultType 進(jìn)行輸出映射,只有查詢(xún)出來(lái)的列名和 pojo 中的屬性名一致,該列才可以映射成功。
如果查詢(xún)出來(lái)的列名和 pojo 中的屬性名全部不一致,沒(méi)有創(chuàng)建 pojo 對(duì)象。
只要查詢(xún)出來(lái)的列名和 pojo 中的屬性有一個(gè)一致,就會(huì)創(chuàng)建 pojo 對(duì)象。
需求:用戶(hù)信息綜合查詢(xún)列表總數(shù),通過(guò)查詢(xún)總數(shù)和上邊用戶(hù)綜合查詢(xún)列表才可以實(shí)現(xiàn)分頁(yè)
實(shí)現(xiàn):
//用戶(hù)信息綜合查詢(xún)總數(shù) public int findUserCount(UserQueryVo userQueryVo) throws Exception;
//測(cè)試用戶(hù)信息綜合查詢(xún)總數(shù) @Test public void testFindUserCount() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); //創(chuàng)建usermapper對(duì)象,mybatis自動(dòng)生成代理對(duì)象 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //創(chuàng)建包裝對(duì)象,設(shè)置查詢(xún)條件 UserQueryVo userQueryVo = new UserQueryVo(); UserCustom userCustom = new UserCustom(); userCustom.setSex("男"); userCustom.setUsername("張小明"); userQueryVo.setUserCustom(userCustom); //調(diào)用UserMapper的方法 System.out.println(userMapper.findUserCount(userQueryVo)); }
注意:查詢(xún)出來(lái)的結(jié)果集只有一行且一列,可以使用簡(jiǎn)單類(lèi)型進(jìn)行輸出映射。
輸出pojo對(duì)象和pojo列表
不管是輸出的pojo單個(gè)對(duì)象還是一個(gè)列表(list中包括pojo),在mapper.xml中resultType指定的類(lèi)型是一樣的。
在mapper.java指定的方法返回值類(lèi)型不一樣:
1、輸出單個(gè)pojo對(duì)象,方法返回值是單個(gè)對(duì)象類(lèi)型
//根據(jù)id查詢(xún)用戶(hù)信息 public User findUserById(int id) throws Exception;
2、輸出pojo對(duì)象list,方法返回值是List
//根據(jù)用戶(hù)名查詢(xún)用戶(hù)信息 public ListfindUserByUsername(String userName) throws Exception;
resultType總結(jié):
輸出pojo對(duì)象和輸出pojo列表在sql中定義的resultType是一樣的。
返回單個(gè)pojo對(duì)象要保證sql查詢(xún)出來(lái)的結(jié)果集為單條,內(nèi)部使用session.selectOne方法調(diào)用,mapper接口使用pojo對(duì)象作為方法返回值。
返回pojo列表表示查詢(xún)出來(lái)的結(jié)果集可能為多條,內(nèi)部使用session.selectList方法,mapper接口使用List
resultMap
resultType 可以指定 pojo 將查詢(xún)結(jié)果映射為 pojo,但需要 pojo 的屬性名和 sql 查詢(xún)的列名一致方可映射成功。
如果sql查詢(xún)字段名和pojo的屬性名不一致,可以通過(guò)resultMap將字段名和屬性名作一個(gè)對(duì)應(yīng)關(guān)系 ,resultMap實(shí)質(zhì)上還需要將查詢(xún)結(jié)果映射到pojo對(duì)象中。
resultMap可以實(shí)現(xiàn)將查詢(xún)結(jié)果映射為復(fù)雜類(lèi)型的pojo,比如在查詢(xún)結(jié)果映射對(duì)象中包括pojo和list實(shí)現(xiàn)一對(duì)一查詢(xún)和一對(duì)多查詢(xún)。
使用方法:
1、定義 resultMap
2、使用 resultMap 作為 statement 的輸出映射類(lèi)型
將下面的 sql 使用 User 完成映射
select id id_, username username_ from user where id = #{value}
User 類(lèi)中屬性名和上邊查詢(xún)的列名不一致。
所以需要:
1、定義 resultMap
2、使用 resultMap 作為 statement 的輸出映射類(lèi)型
3、UserMapper.java
//根據(jù)id查詢(xún)用戶(hù)信息,使用 resultMap 輸出 public User findUserByIdResultMap(int id) throws Exception;
4、測(cè)試
//測(cè)試根據(jù)id查詢(xún)用戶(hù)信息,使用 resultMap 輸出 @Test public void testFindUserByIdResultMap() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); //創(chuàng)建usermapper對(duì)象,mybatis自動(dòng)生成代理對(duì)象 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //調(diào)用UserMapper的方法 User user = userMapper.findUserByIdResultMap(1); System.out.println(user); }
5、測(cè)試結(jié)果
動(dòng)態(tài) SQL通過(guò)mybatis提供的各種標(biāo)簽方法實(shí)現(xiàn)動(dòng)態(tài)拼接sql。
需求:
用戶(hù)信息綜合查詢(xún)列表和用戶(hù)信息查詢(xún)列表總數(shù)這兩個(gè) statement的定義使用動(dòng)態(tài)sql。
對(duì)查詢(xún)條件進(jìn)行判斷,如果輸入的參數(shù)不為空才進(jìn)行查詢(xún)條件拼接。
UserMapper.xml (findUserList的配置如下,那么findUserCount的也是一樣的,這里就不全部寫(xiě)出來(lái)了)
測(cè)試代碼:因?yàn)樵O(shè)置了動(dòng)態(tài)的sql,如果不設(shè)置某個(gè)值,那么條件就不會(huì)拼接在sql上
所以我們就注釋掉設(shè)置username的語(yǔ)句
//userCustom.setUsername("張小明");
測(cè)試結(jié)果:
Sql 片段通過(guò)上面的其實(shí)看到在 where sql語(yǔ)句中有很多重復(fù)代碼,我們可以將其抽取出來(lái),組成一個(gè)sql片段,其他的statement就可以引用這個(gè)sql片段,利于系統(tǒng)的開(kāi)發(fā)。
這里我們就拿上邊sql 中的where定義一個(gè)sq片段如下:
and user.sex = #{userCustom.sex} and user.username like "%${userCustom.username}%"
那么我們?cè)撛鯓右眠@個(gè)sql片段呢?如下:
select * from user
測(cè)試的話(huà)還是那樣了,就不繼續(xù)說(shuō)了,前面已經(jīng)說(shuō)了很多了。
foreach向sql傳遞數(shù)組或List,mybatis使用foreach解析
需求:
在用戶(hù)查詢(xún)列表和查詢(xún)總數(shù)的statement中增加多個(gè)id輸入查詢(xún)。
sql語(yǔ)句如下:
SELECT * FROM USER WHERE id=1 OR id=10 ORid=16 或者 SELECT * FROM USER WHERE id IN(1,10,16)
在輸入?yún)?shù)類(lèi)型中添加 List
public class UserQueryVo //用戶(hù)包裝類(lèi)型 { //傳入多個(gè)id private Listids; }
修改 UserMapper.xml文件
WHERE id=1 OR id=10 OR id=16
在查詢(xún)條件中,查詢(xún)條件定義成一個(gè)sql片段,需要修改sql片段。
id=#{user_id}
測(cè)試代碼:
//傳入多個(gè)id Listids = new ArrayList<>(); ids.add(1); ids.add(10); ids.add(16); //將ids傳入statement中 userQueryVo.setIds(ids);
期待后續(xù)的文章吧!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/66298.html
摘要:場(chǎng)合常見(jiàn)一些明細(xì)記錄的展示,比如用戶(hù)購(gòu)買(mǎi)商品明細(xì),將關(guān)聯(lián)查詢(xún)信息全部展示在頁(yè)面時(shí),此時(shí)可直接使用將每一條記錄映射到中,在前端頁(yè)面遍歷中是即可。作用將關(guān)聯(lián)查詢(xún)信息映射到一個(gè)對(duì)象中。 相關(guān)閱讀: 1、通過(guò)項(xiàng)目逐步深入了解Mybatis 2、 通過(guò)項(xiàng)目逐步深入了解Mybatis 本項(xiàng)目所有代碼及文檔都托管在 Github地址:https://github.com/zhisheng17/myb...
摘要:解決方法使用數(shù)據(jù)庫(kù)連接池管理數(shù)據(jù)庫(kù)連接。向中設(shè)置參數(shù),對(duì)占位符號(hào)位置和設(shè)置參數(shù)值,硬編碼在代碼中,同樣也不利于系統(tǒng)的維護(hù)。從中遍歷結(jié)果集數(shù)據(jù)時(shí),存在硬編碼,將獲取表的字段進(jìn)行硬編碼,不利于系統(tǒng)維護(hù)。 Mybatis Mybatis 和 SpringMVC 通過(guò)訂單商品案例驅(qū)動(dòng) 官方中文地址:http://www.mybatis.org/mybati... 官方托管地址:https://...
摘要:從使用到原理學(xué)習(xí)線(xiàn)程池關(guān)于線(xiàn)程池的使用,及原理分析分析角度新穎面向切面編程的基本用法基于注解的實(shí)現(xiàn)在軟件開(kāi)發(fā)中,分散于應(yīng)用中多出的功能被稱(chēng)為橫切關(guān)注點(diǎn)如事務(wù)安全緩存等。 Java 程序媛手把手教你設(shè)計(jì)模式中的撩妹神技 -- 上篇 遇一人白首,擇一城終老,是多么美好的人生境界,她和他歷經(jīng)風(fēng)雨慢慢變老,回首走過(guò)的點(diǎn)點(diǎn)滴滴,依然清楚的記得當(dāng)初愛(ài)情萌芽的模樣…… Java 進(jìn)階面試問(wèn)題列表 -...
閱讀 1358·2021-11-24 09:39
閱讀 3709·2021-09-02 15:21
閱讀 2249·2021-08-24 10:01
閱讀 802·2021-08-19 10:55
閱讀 2540·2019-08-30 15:55
閱讀 1304·2019-08-30 14:16
閱讀 3107·2019-08-29 15:17
閱讀 3324·2019-08-29 13:53