Oraclemybatis 以更总结

一致、多数据源问题

着重思路是管dataSource、sqlSesstionFactory、MapperScannerConfigurer在部署中区分开,各Mapper对应的包名、类名区分开

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
 4        xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
 5        xmlns:context="http://www.springframework.org/schema/context"
 6        xsi:schemaLocation="
 7      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
 8      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
 9      http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
10      http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
11      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
12        default-autowire="byName">
13 
14     <bean id="dataSource1" class="org.h2.jdbcx.JdbcConnectionPool"
15           destroy-method="dispose">
16         <constructor-arg>
17             <bean class="org.h2.jdbcx.JdbcDataSource">
18                 <property name="URL" value="jdbc:h2:r:/h2db/awbprint/a"/>
19                 <property name="user" value="sa"/>
20                 <property name="password" value="sa"/>
21             </bean>
22         </constructor-arg>
23     </bean>
24 
25 
26     <bean id="dataSource2" class="org.h2.jdbcx.JdbcConnectionPool"
27           destroy-method="dispose">
28         <constructor-arg>
29             <bean class="org.h2.jdbcx.JdbcDataSource">
30                 <property name="URL" value="jdbc:h2:r:/h2db/awbprint/b"/>
31                 <property name="user" value="sa"/>
32                 <property name="password" value="sa"/>
33             </bean>
34         </constructor-arg>
35     </bean>
36 
37     <bean id="sqlSessionFactory1" class="org.mybatis.spring.SqlSessionFactoryBean">
38         <property name="dataSource" ref="dataSource1"/>
39         <property name="configLocation" value="classpath:mybatis-config.xml"></property>
40         <property name="typeAliasesPackage" value="awbprint.mybatis.entity"></property>
41         <property name="mapperLocations" value="classpath:mybatis/a/**/*.xml"></property>
42     </bean>
43 
44     <bean id="sqlSessionFactory2" class="org.mybatis.spring.SqlSessionFactoryBean">
45         <property name="dataSource" ref="dataSource2"/>
46         <property name="configLocation" value="classpath:mybatis-config.xml"></property>
47         <property name="typeAliasesPackage" value="awbprint.mybatis.entity"></property>
48         <property name="mapperLocations" value="classpath:mybatis/b/**/*.xml"></property>
49     </bean>
50 
51     <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
52         <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory1"></property>
53         <property name="basePackage" value="awbprint.mybatis.mapper.a"/>
54     </bean>
55 
56     <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
57         <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory2"></property>
58         <property name="basePackage" value="awbprint.mybatis.mapper.b"/>
59     </bean>
60 
61 
62 </beans>

点的布,一个连h2的a数据库,一个连h2的b数据库,至于事务管理器,大家只是参看这思路,建二只,各管各的。

项目蒙mapper接口及射文件都用包名区分开,如下图:

Oracle 1

 

第二、如何使Map做呢参数与动态条件转

 1     <resultMap id="BaseResultMap" type="awbprint.mybatis.entity.PrintLayout">
 2         <id column="D_RECID" property="recid" jdbcType="DECIMAL"/>
 3         <result column="D_USER_NAME" property="userName" jdbcType="VARCHAR"/>
 4         <result column="D_NAME" property="name" jdbcType="VARCHAR"/>
 5         <result column="D_TYPE" property="type" jdbcType="VARCHAR"/>
 6         ...
 7        
 8     </resultMap>
 9 
10    <sql id="Base_Column_List">
11         D_RECID, D_USER_NAME, D_NAME, D_TYPE, ...
12     </sql>
13 
14     <select id="select" resultMap="BaseResultMap"
15             parameterType="java.util.Map">
16         select
17         <include refid="Base_Column_List"/>
18         from T_PRINT_LAYOUT
19         where D_USER_NAME = #{userName,jdbcType=VARCHAR} and D_TYPE = #{awbType,jdbcType=VARCHAR}
20         <if test="recId != null">
21             and D_RECID = #{recId,jdbcType=DECIMAL}
22         </if>
23         <if test="ids != null">
24             or D_RECID in
25             <foreach item="item" index="index" collection="ids"
26                      open="(" separator="," close=")">
27                 #{item}
28             </foreach>
29         </if>
30 
31     </select>

14-31演示了哪使用Map做为参数,动态传入查询条件,及List参数生成in(…)条件

java端代码示例:

 1         PrintLayoutMapper mapper = context.getBean(PrintLayoutMapper.class);
 2         
 3         Map<String, Object> map = new HashMap<String, Object>();
 4         map.put("userName", "ADMIN");
 5         map.put("awbType", "CARGOLABEL_MU");
 6         map.put("recId", 1);
 7         
 8         List<Integer> ids = new ArrayList<Integer>();
 9         ids.add(0, 1);
10         ids.add(0, 2);
11         ids.add(0, 3);
12         
13         map.put("ids", ids);
14 
15         List<?> list = mapper.select(map);

实则PrintLayoutMapper接口的概念也:

1 public interface PrintLayoutMapper {    
2     ...
3     
4     List<PrintLayout> select(Map<String, Object> map);
5 }

末生成的SQL语句也:

1 select D_RECID, D_USER_NAME, D_NAME, D_TYPE, ... from T_PRINT_LAYOUT where D_USER_NAME = ? and D_TYPE = ? and D_RECID = ? or D_RECID in ( ? , ? , ? )

 

老三、兼容不同的数据库

 1 <insert id="insert">
 2  <selectKey keyProperty="id" resultType="int" order="BEFORE">
 3  <if test="_databaseId == 'oracle'">
 4  select seq_users.nextval from dual
 5  </if>
 6  <if test="_databaseId == 'db2'">
 7  select nextval for seq_users from sysibm.sysdummy1"
 8  </if>
 9  </selectKey>
10  insert into users values (#{id}, #{name})
11 </insert>

立马是官文档上的言传身教,演示了哪兼容oracle与db2顿时第二栽不同的数据库,来取序列的下一个价值

 

季、加强版本的分支、选择判断

 1 <select id="findActiveBlogLike"
 2  resultType="Blog">
 3  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
 4  <choose>
 5  <when test="title != null">
 6  AND title like #{title}
 7  </when>
 8  <when test="author != null and author.name != null">
 9  AND author_name like #{author.name}
10  </when>
11  <otherwise>
12  AND featured = 1
13  </otherwise>
14  </choose>
15 </select>

顿时也是官文档上之演示,因为<if>…</if>并从未相应的<else>标签,所以只要高达<if>…<else>…</else>
</if>的成效,得仰仗<choose>、<when>、<otherwise>组合使用。

 

五、避免Where 空条件的尴尬

1 <select id="findActiveBlogLike" resultType="Blog">
2  SELECT * FROM BLOG
3  WHERE
4  <if test="state != null">
5  state = #{state}
6  </if> 
7 </select>

若是state参数为空时,最终生成SQL语句也 

1  SELECT * FROM BLOG
2  WHERE

履行会出错,当然,你得于where 后加以一个1=1,改成为

1 <select id="findActiveBlogLike" resultType="Blog">
2  SELECT * FROM BLOG
3  WHERE 1=1
4  <if test="state != null">
5  and state = #{state}
6  </if> 
7 </select>

而这做法不顶“环保”(毕竟引入了一个废弃物条件),其实要改变成为<where>…</where>即可

1 <select id="findActiveBlogLike" resultType="Blog">
2  SELECT * FROM BLOG
3  <where>
4      <if test="state != null">
5          and state = #{state}
6      </if>
7  </where> 
8 </select>

 

六、$与#的区别

1  select * from T_PRINT_LAYOUT where  D_RECID = ${recId}

末段生成的SQL为:

1 select * from T_PRINT_LAYOUT where  D_RECID = 1

就是:直接用参数值替换到了原${recId}的岗位,相当给刚拼SQL

 

1  select * from T_PRINT_LAYOUT where  D_RECID = #{recid,jdbcType=DECIMAL}

最终生成的SQL为:

1 select * from T_PRINT_LAYOUT where  D_RECID = ?

即:#{…}被辨认为一个SQL参数

 

七、大量数目的批量insert

汪洋数额(条数>10000)做insert时,如果以正常方法,每条insert into
table(…)
values(…);来交给,速度巨慢。改善性的笔触是基本上修insert批量提交。

oracle环境遭到,有一样栽批量insert的微技巧,原理是 insert into … select
from …,套于mybatis上,变形也:

 1 INSERT INTO T_TEST
 2   (ID, COL_A, COL_B)
 3   SELECT SEQ_TEST.NEXTVAL, A.*
 4     FROM (
 5               SELECT 'A1', 'B1' FROM DUAL
 6     UNION ALL SELECT 'A2', 'B2' FROM DUAL
 7     UNION ALL SELECT 'A3', 'B3' FROM DUAL
 8     UNION ALL SELECT 'A4', 'B4' FROM DUAL
 9     UNION ALL SELECT 'A5', 'B5' FROM DUAL
10     UNION ALL SELECT 'A6', 'B6' FROM DUAL
11     ) A

中级的一对大有规律,可以用foreach标签生成,参考下面的组成部分:

 1 <insert id="insertBatch2" parameterType="ctas.entity.SharkFlt">
 2     <selectKey keyProperty="recId" order="BEFORE" resultType="Long">
 3       select SEQ_CTAS_SHARK_FLT.nextval as recId from dual
 4     </selectKey>
 5     insert into CTAS_SHARK_FLT (<include refid="Base_Column_List"/>) SELECT SEQ_TEST.NEXTVAL, A.*
 6     FROM (
 7     <foreach collection="list" item="item" index="index" open="" close="" separator="union all">
 8       select #{item.awbType,jdbcType=VARCHAR}, #{item.awbPre,jdbcType=VARCHAR},... from dual
 9     </foreach>
10     ) A
11   </insert>

便如此,也未可知直接run,oracle中相同不善实践之sql语句长度是来限量的,如果最后拼下的sql字符串过长,会招执行破产,所以java端还要举行一个分层处理,参考下面的处理:

 1         List<SharkFlt> data = new ArrayList<SharkFlt>();
 2         for (TSharkFlt f : sharkFlts) {
 3             data.add(getSharkFlt(f));
 4         }
 5 
 6         System.out.println(data.size());
 7 
 8         long beginTime = System.currentTimeMillis();
 9         System.out.println("开始插入...");
10         SqlSessionFactory sqlSessionFactory = ctx.getBean(SqlSessionFactory.class);
11         SqlSession session = null;
12         try {
13             session = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
14             int a = 2000;//每次提交2000条
15             int loop = (int) Math.ceil(data.size() / (double) a);
16 
17             List<SharkFlt> tempList = new ArrayList<SharkFlt>(a);
18             int start, stop;
19             for (int i = 0; i < loop; i++) {
20                 tempList.clear();
21                 start = i * a;
22                 stop = Math.min(i * a + a - 1, data.size() - 1);
23                 System.out.println("range:" + start + " - " + stop);
24                 for (int j = start; j <= stop; j++) {
25                     tempList.add(data.get(j));
26                 }
27                 session.insert("ctas.importer.writer.mybatis.mappper.SharkFltMapper.insertBatch2", tempList);
28                 session.commit();
29                 session.clearCache();
30                 System.out.println("已经插入" + (stop + 1) + " 条");
31             }
32         } catch (Exception e) {
33             e.printStackTrace();
34             session.rollback();
35         } finally {
36             if (session != null) {
37                 session.close();
38             }
39         }
40         long endTime = System.currentTimeMillis();
41         System.out.println("插入完成,耗时 " + (endTime - beginTime) + " 毫秒!");

13,27-29立马几推行是重大,这无异截逻辑会经常使用,为了用,可以打包一下:

 1     /**
 2      * 批量提交数据
 3      * @param sqlSessionFactory
 4      * @param mybatisSQLId SQL语句在Mapper XML文件中的ID
 5      * @param commitCountEveryTime 每次提交的记录数
 6      * @param list 要提交的数据列表
 7      * @param logger 日志记录器
 8      */
 9     private <T> void batchCommit(SqlSessionFactory sqlSessionFactory, String mybatisSQLId, int commitCountEveryTime, List<T> list, Logger logger) {
10         SqlSession session = null;
11         try {
12             session = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
13             int commitCount = (int) Math.ceil(list.size() / (double) commitCountEveryTime);
14             List<T> tempList = new ArrayList<T>(commitCountEveryTime);
15             int start, stop;
16             Long startTime = System.currentTimeMillis();
17             for (int i = 0; i < commitCount; i++) {
18                 tempList.clear();
19                 start = i * commitCountEveryTime;
20                 stop = Math.min(i * commitCountEveryTime + commitCountEveryTime - 1, list.size() - 1);
21                 for (int j = start; j <= stop; j++) {
22                     tempList.add(list.get(j));
23                 }
24                 session.insert(mybatisSQLId, tempList);
25                 session.commit();
26                 session.clearCache();
27             }
28             Long endTime = System.currentTimeMillis();
29             logger.debug("batchCommit耗时:" + (endTime - startTime) + "毫秒");
30         } catch (Exception e) {
31             logger.error("batchCommit error!", e);
32             e.printStackTrace();
33             session.rollback();
34         } finally {
35             if (session != null) {
36                 session.close();
37             }
38         }
39     }

对应之,如果是批量update,也是接近之思路,只不过要留心一点:oracle环境面临,多漫长告词提交的sql语句也

begin

  update xxx set xxx =xxx ;

  update xxx set xxx =xxx;

end;

据此mytais拼的时节,参考下面的写法:

1   <update id="updateBatch" parameterType="java.util.List">
2     <foreach collection="list" item="item" index="index" open="begin" close="end;" >
3       update xxx set x=#{item.x,jdbcType=VARCHAR} where x =#{item.x,jdbcType=VARCHAR};
4     </foreach>
5   </update>

至于批量付的属性,Oracle环境下,我大概测试了一下:

insert into … select xxx

  union all select yyy

  union all select zzz;

最快,其次是

begin

  insert into … values  …;

  insert into … values …;

end;

理所当然最慢是逐一长insert提交,最后称下Spring与mybatis集成后,AOP事务管理 对
批量提交的震慑 ,通常状态下,我们会这样安排AOP事务管理:

 1     <tx:advice id="txAdvice" transaction-manager="transactionManager">
 2         <tx:attributes>
 3             <tx:method name="do*" read-only="false" rollback-for="java.lang.Exception"/>
 4             <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
 5         </tx:attributes>
 6     </tx:advice>
 7 
 8     <aop:config>
 9         <aop:pointcut id="pc" expression="execution(* ctas.service.*.*(..))"/>
10         <aop:advisor pointcut-ref="pc" advice-ref="txAdvice"/>
11     </aop:config>

这样,ctas.service(及子包)下之拥有办法还叫阻止,而且只有do开头的办法,具有可写的事情(即:能insert/update/delete记录),而其余措施是一味念事务(即:只能select数据),但是咱前面说到之批量交到操作,都是描摹代码手动提交的,不待spring管理,所以安排中待用或多或少方法排除,可以大致定self开头的措施,由开发者自己管理事务,不待spring代为管理,上面的部署要改成化:

1     <aop:config>
2         <aop:pointcut id="pc" expression="execution(* ctas.service.*.*(..)) and !execution(* ctas.service.*.self*(..)))"/>
3         <aop:advisor pointcut-ref="pc" advice-ref="txAdvice"/>
4     </aop:config>

 通过 and !execution(…)
将self开头的法子排除就得了,前面的批量操作代码写及selfXXX方法吃。

 

至于批量交付,还有平等栽情形:父子表的批量插。思路或一样的,但是SQL的写法有点区别,原理参考下面的口舌(Oracle环境)

 1 DECLARE
 2   BASE_ID   INTEGER;
 3   DETAIL_ID INTEGER;
 4 BEGIN
 5   --第1组记录
 6   SELECT SEQ_T_BASE.NEXTVAL INTO BASE_ID FROM DUAL;
 7   INSERT INTO T_BASE (ID, FEE) VALUES (BASE_ID, ?);
 8   
 9   SELECT SEQ_T_DETAIL.NEXTVAL INTO DETAIL_ID FROM DUAL;
10   INSERT INTO T_DETAIL (ID, BASE_ID, FEE) VALUES (DETAIL_ID, BASE_ID, ?);
11   SELECT SEQ_T_DETAIL.NEXTVAL INTO DETAIL_ID FROM DUAL;
12   INSERT INTO T_DETAIL (ID, BASE_ID, FEE) VALUES (DETAIL_ID, BASE_ID, ?);
13   
14   --第2组记录
15   SELECT SEQ_T_BASE.NEXTVAL INTO BASE_ID FROM DUAL;
16   INSERT INTO T_BASE (ID, FEE) VALUES (BASE_ID, ?);
17   
18   SELECT SEQ_T_DETAIL.NEXTVAL INTO DETAIL_ID FROM DUAL;
19   INSERT INTO T_DETAIL (ID, BASE_ID, FEE) VALUES (DETAIL_ID, BASE_ID, ?);
20   SELECT SEQ_T_DETAIL.NEXTVAL INTO DETAIL_ID FROM DUAL;
21   INSERT INTO T_DETAIL (ID, BASE_ID, FEE) VALUES (DETAIL_ID, BASE_ID, ?);
22   
23   --...
24 END;

 

xml映射文件被的写法:

 1     <insert id="insertBatch" parameterType="java.util.List">
 2         DECLARE
 3         base_id INTEGER ;
 4         detail_id INTEGER ;
 5         <foreach collection="list" item="item" index="index" open="begin" close="end;">
 6             select seq_t_base.nextval into base_id from dual;
 7             insert into t_base(id, fee) values(base_id, #{item.baseEntity.fee,jdbcType=DECIMAL});
 8             <foreach collection="item.details" item="detail" index="index">
 9                 select seq_t_detail.nextval into detail_id from dual;
10                 insert into t_detail(id, base_id, fee) values(detail_id,base_id,#{detail.fee,jdbcType=DECIMAL});
11             </foreach>
12         </foreach>
13     </insert>

 List中的Dto定义

 1 public class BaseDetailDto {
 2 
 3     private TBase baseEntity;
 4 
 5     private List<TDetail> details;
 6 
 7     public TBase getBaseEntity() {
 8         return baseEntity;
 9     }
10 
11     public void setBaseEntity(TBase baseEntity) {
12         this.baseEntity = baseEntity;
13     }
14 
15 
16     public List<TDetail> getDetails() {
17         return details;
18     }
19 
20     public void setDetails(List<TDetail> details) {
21         this.details = details;
22     }
23 }

 

相关文章