網(wǎng)頁設計軟件應用廣州seo公司哪個比較好
專欄精選
引入Mybatis
Mybatis的快速入門
Mybatis的增刪改查擴展功能說明
mapper映射的參數(shù)和結(jié)果
Mybatis復雜類型的結(jié)果映射
Mybatis基于注解的結(jié)果映射
Mybatis枚舉類型處理和類型處理器
再談動態(tài)SQL
Mybatis配置入門
Mybatis行為配置之Ⅰ—緩存
Mybatis行為配置之Ⅱ—結(jié)果相關配置項說明
文章目錄
- 專欄精選
- 引言
- 摘要
- 正文
- defaultExecutorType
- defaultStatementTimeout
- defaultResultSetType
- safeRowBoundsEnabled
- safeResultHandlerEnabled
- jdbcTypeForNull
- defaultScriptingLanguage
- defaultEnumTypeHandler
- callSettersOnNulls
- useActualParamName
- returnInstanceForEmptyRow
- 總結(jié)
引言
大家好,我是奇跡老李,一個專注于分享開發(fā)經(jīng)驗和基礎教程的博主。歡迎來到我的頻道,這里匯聚了匯集編程技巧、代碼示例和技術教程,歡迎廣大朋友們點贊評論提出意見,重要的是點擊關注喔 🙆,期待在這里與你共同度過美好的時光🕹?。今天要和大家分享的內(nèi)容是Mybatis行為配置之Ⅲ—其他常用配置項說明。做好準備,Let’s go🚎🚀
摘要
在這篇文章中,我們將了解剩下的關于Mybatis行為的配置,在mybatis項目開發(fā)過程中這些配置可能并不常用,而且大多數(shù)情況下都是使用默認配置,了解這些配置的意義可以讓我們在解決很多罕見異常問題時有的放矢,不至于手忙腳亂。那么準備好開啟今天的神奇之旅了嗎?
正文
今天我們介紹Mybatis中最后幾個控制Mybatis行為的配置項,它們是
defaultExecutorType
備注:配置默認的執(zhí)行器。
默認值:SIMPLE
可選值:
值 | 說明 | 對應的Executor實現(xiàn)類 |
---|---|---|
SIMPLE | 普通的執(zhí)行器,使用JDBC默認Statement | SimpleExecutor |
REUSE | 預處理語句執(zhí)行器,使用JDBC的PreparedStatement | ReuseExecutor |
BATCH | 重用語句+批量更新執(zhí)行器 | BatchExecutor |
建議值:SIMPLE
建議原因:SIMPLE比較通用。如果有特殊需求,可以通過 SqlSessionFactoryBuilder#openSession(ExecutorType execType)
方法獲取到包含對應的Executor的SqlSession。
注:Executor
保存在 org.apache.ibatis.session.defaults.DefaultSqlSession
類中。
批量插入數(shù)據(jù)的代碼示例
public class EnvConfigTest { private SqlSessionFactory sqlSessionFactory; private SqlSession sqlSession; @Test public void testBatchInsert(){ List<AppTestEntity> list=new ArrayList<>(); AppTestEntityBuilder builder = new AppTestEntityBuilder(); builder.setAppName("test-name").setAppCode("test-name-code").setAuthType("1").setCreator("junit"); list.add(builder.build()); //省略n個list.add //關鍵在ExecutorType.BATCH SqlSession session = this.sqlSessionFactory.openSession(ExecutorType.BATCH); ApplicationRepository mapper = session.getMapper(ApplicationRepository.class); list.stream().forEach(o->{ mapper.addApp(o); }); session.commit(); session.close(); } }
defaultStatementTimeout
備注:等待數(shù)據(jù)庫響應的秒數(shù)。這項配置需要數(shù)據(jù)庫驅(qū)動的支持,在Mysql中此項配置基本無效,在postgres數(shù)據(jù)庫中此配置有效
默認值:null
可選值:任意正整數(shù)
建議值:根據(jù)實際情況設置
建議原因:取決于數(shù)據(jù)庫硬件和配置
Postgres配置下的測試代碼:
public class PostgresTest { private SqlSessionFactory sqlSessionFactory; private SqlSession sqlSession; @Before public void before(){ try (InputStream inputStream = PostgresTest.class.getResourceAsStream("/mybatis-config.xml")){ this.sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream,"postgres9"); this.sqlSession=this.sqlSessionFactory.openSession(); } catch (IOException e) { throw new RuntimeException(e); } } @After public void after(){ this.sqlSession.clearCache(); this.sqlSession.close(); } //新增十萬條數(shù)據(jù)@Test public void testBatchInsert(){ List<AppTestEntity> list=new ArrayList<>(); AppTestEntityBuilder builder = new AppTestEntityBuilder(); builder.setAppName("test-name").setAppCode("test-name-code").setAuthType("1").setCreator("junit"); for (int i = 0; i < 100000; i++) { AppTestEntity e = builder.build(); e.setId(((long) i+1)); list.add(e); } //省略n個list.add SqlSession session = this.sqlSessionFactory.openSession(ExecutorType.BATCH); ApplicationRepository mapper = session.getMapper(ApplicationRepository.class); list.stream().forEach(o->{ mapper.addApp(o); }); session.commit(); session.close(); } //查詢測試@Test public void testFetchSize(){ SimpleQueryMapper mapper = this.sqlSession.getMapper(SimpleQueryMapper.class); long start = System.currentTimeMillis(); List<AppTestEntity> list = mapper.queryList("1"); long gap = System.currentTimeMillis() - start; System.out.println("selected result size: "+list.size()); System.out.println("selected time: "+gap); }
}
配置 <setting name="defaultFetchSize" value="1"/>
后的輸出
selected result size: 100000
selected time: 8994
配置 <setting name="defaultFetchSize" value="1000"/>
后的輸出
selected result size: 100000
selected time: 413
不配置情況下的輸出
selected result size: 100000
selected time: 418
細節(jié) 這里需要注意,此配置會被 fetchSize
屬性覆蓋。fetchSize可以通過以下方式設置
- 注解的方式
@Select(value = "select * from app_test where auth_type=#{type}")
@Options(fetchSize = 1000)
List<AppTestEntity> queryList(@Param("type") String type);
- 標簽的方式
<select id="queryList" resultType="AppTestEntity" fetchSize="1000"> select * from app_test where auth_type=#{type}
</select>
defaultResultSetType
備注:指定語句默認的滾動策略
可選值:
配置值 | 說明 |
---|---|
FORWARD_ONLY | 索引只能向后方滾動,不能往前 |
SCROLL_SENSITIVE | 索引可向前后滾動,且更新敏感 |
SCROLL_INSENSITIVE | 索引可向前后滾動,且更新不敏感 |
DEFAULT | 默認,效果和不設置相同 |
默認值:null(DEFAULT)
建議值:不設置
建議原因:不常用,此配置是對jdbc的行為控制,而在mybatis項目中不會直接操作jdbc
safeRowBoundsEnabled
備注:是否允許在嵌套語句(子查詢)中使用分頁API(RowBounds)。如果允許使用則設置為 false
默認值:false
建議值:
建議原因:
此配置常見的生效情況是,調(diào)用了 sqlSession#selectList(String statement,Object param,RowBounds rowBounds)
這個方法,而參數(shù)statement
又是嵌套語句,如以下測試代碼:
@Test
public void testSafeRow(){ List objects = this.sqlSession.selectList("top.sunyog.mybatis.mapper.SimpleQueryMapper.queryAppDetail", 1, new RowBounds(0, 1)); for (Object obj : objects) { System.out.println(obj); }
}
此代碼在默認配置情況下可以正常輸出
AppTestEntity{id=null, appName='測試應用1', appCode='ceshi', authType='1', createDate=2023-10-31, creator='admin', appStatus='3', authTypeDict=DictTest{dictName='NONE', dictCode='1', dictType='app_auth_type', dictSort=0}, appStatusDict=DictTest{dictName='正常應用', dictCode='3', dictType='app_status', dictSort=0}, services=[ServiceTestEntity{id=3, serviceName='注冊中心', serviceCode='nacos-service', servicePath='/nacos', appId=1}]}
而配置 <setting name="safeRowBoundsEnabled" value="true"/>
后,會報錯
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: org.apache.ibatis.executor.ExecutorException: Mapped Statements with nested result mappings cannot be safely constrained by RowBounds. Use safeRowBoundsEnabled=false setting to bypass this check.
### The error may exist in mapper/SimpleQueryMapper.xml
### The error may involve top.sunyog.mybatis.mapper.SimpleQueryMapper.queryAppDetail
### The error occurred while handling results
### SQL: select t1.* ,t2.dict_code as auth_type_dc,t2.dict_name as auth_type_dn,t2.dict_type as auth_type_dt,t2.dict_sort as auth_type_ds from ( select id,app_name,app_code,auth_type,create_date,creator,app_status from app_test where id=? ) t1 left join ( select dict_code,dict_name,dict_type,dict_sort from dict_test where dict_type='app_auth_type' ) t2 on t1.auth_type=t2.dict_code
### Cause: org.apache.ibatis.executor.ExecutorException: Mapped Statements with nested result mappings cannot be safely constrained by RowBounds. Use safeRowBoundsEnabled=false setting to bypass this check.
safeResultHandlerEnabled
備注:是否允許在嵌套語句中使用結(jié)果處理器(ResultHandler)。如果允許使用則設置為 false
默認值:true
建議值:按實際情況設置
建議原因:
結(jié)果處理器ResultHandler的使用方法見Mybatis基于注解的結(jié)果映射這篇文章
jdbcTypeForNull
備注:當沒有為參數(shù)指定特定的 JDBC 類型時,空值的默認 JDBC 類型。 某些數(shù)據(jù)庫驅(qū)動需要指定列的 JDBC 類型,多數(shù)情況直接用一般類型即可,比如 NULL、VARCHAR 或 OTHER
可選值:org.apache.ibatis.type.JdbcType
常量
默認值:OTHER
建議值:不設置
建議原因:
defaultScriptingLanguage
備注:指定動態(tài) SQL 生成使用的默認腳本語言。
默認值:org.apache.ibatis.scripting.xmltags.XMLLanguageDriver
建議值:不設置
建議原因:不常用
defaultEnumTypeHandler
備注:指定枚舉類型的默認TypeHandler
,關于枚舉類型的TypeHandler使用示例,見[[Mybatis基礎#枚舉類型映射]]
默認值:EnumTypeHandler
建議值:按實際情況設置,建議設置為 EnumOrdinalTypeHandler
建議原因:實際應用中,枚舉類型大多數(shù)都是順序編碼的字典值
callSettersOnNulls
備注:指定當結(jié)果集中值為 null 的時候是否調(diào)用映射對象的 setter(map 對象時為 put)方法
默認值:false
建議值:true
建議原因:返回值中某個字段為null時,再map對象中也會插入這個對應的key,這樣可以減少對map的 containsKey
方法操作。
通過以下代碼測試設置的行為
@Test
public void testNullSet(){ SimpleQueryMapper mapper = this.sqlSession.getMapper(SimpleQueryMapper.class); //在這之前先執(zhí)行這個sql//update app_test set creator=null where id=13;List<Map<String, Object>> list = mapper.queryMapRes(13); System.out.println(list);
}
默認設置時的輸出:
[{app_name=test-name, auth_type=1, id=13, create_date=2023-11-30, app_code=test-name-code}]
配置 <setting name="callSettersOnNulls" value="true"/>
時的輸出
[{app_name=test-name, auth_type=1, creator=null, id=13, create_date=2023-11-30, app_code=test-name-code}]
useActualParamName
備注:允許使用方法簽名中的名稱作為語句參數(shù)名稱。 為了使用該特性,項目必須采用 Java 8 編譯,并且加上 -parameters 選項
默認值:true
建議值:true
建議原因:
parameters選項的添加方式為修改maven的pom.xml
文件
細節(jié):這個插件安裝或修改后,需要執(zhí)行maven:clean
和maven:compile
后才能生效
<project>
...<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <compilerArgs> <arg>-parameters</arg> </compilerArgs> </configuration> </plugin> </plugins> </build>
</project>
新增測試代碼
@Test
public void testMethodParam(){ SimpleQueryMapper mapper = this.sqlSession.getMapper(SimpleQueryMapper.class); List<AppTestEntity> list = mapper.getAppByStatusAndAuthType("3","1"); System.out.println(list);
}
public interface SimpleQueryMapper {//注意,這里的入?yún)]有添加@Param注解List<AppTestEntity> getAppByStatusAndAuthType(String status,String authType);
}
<select id="getAppByStatusAndAuthType" resultType="appTestEntity"> <include refid="top.sunyog.mybatis.mapper.ApplicationRepository.query_column"></include> where app_status=#{status} and auth_type=#{authType}
</select>
配置 <setting name="useActualParamName" value="false"/>
后執(zhí)行報錯
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: org.apache.ibatis.binding.BindingException: Parameter 'status' not found. Available parameters are [0, 1, param1, param2]
### Cause: org.apache.ibatis.binding.BindingException: Parameter 'status' not found. Available parameters are [0, 1, param1, param2]
默認配置或 <setting name="useActualParamName" value="true"/>
配置下,打印結(jié)果
[AppTestEntity{id=1, appName='測試應用1', appCode='ceshi', authType='1', createDate=2023-10-31, creator='admin', appStatus='3', authTypeDict=null, appStatusDict=null, services=null}]
returnInstanceForEmptyRow
備注:當返回行的所有列都是空時,默認返回 null。 當開啟這個設置時,MyBatis會返回一個空實例。 請注意,它也適用于嵌套的結(jié)果集
默認值:false
建議值:true
建議原因:可減少空指針驗證
測試代碼
public interface SimpleQueryMapper {@Select("select name,code from empty_table_test where 1=1 limit 0,1") Map<String, Object> queryEmptyMap(int i);
}public class EnvConfigTest {@Test public void testReturnEmptyObj(){ SimpleQueryMapper mapper = this.sqlSession.getMapper(SimpleQueryMapper.class); Map<String,Object> entity = mapper.queryEmptyMap(112); System.out.println(entity); }
}
新增可為空的測試表
create table empty_table_test
( name int null, code varchar(32) null
);
insert into empty_table_test(name,code) values(null,null),(null,null)
默認配置下的輸出
null
配置 <setting name="returnInstanceForEmptyRow" value="true"/>
時的輸出
{}
總結(jié)
今天介紹的配置項在日常工作中很多都不是很常用,但了解這些配置可以減少很多不必要的錯誤,甚至解決一些罕見的異常問題。如 returnInstanceForEmptyRow
這個配置能在很大程度上減少空指針異常的出現(xiàn)。
📩 聯(lián)系方式
郵箱:qijilaoli@foxmail.com?版權聲明
本文為原創(chuàng)文章,版權歸作者所有。未經(jīng)許可,禁止轉(zhuǎn)載。更多內(nèi)容請訪問奇跡老李的博客首頁