myBatis的核心配置

时间:2022-02-08 05:06:24

MyBatis的设计思路

ORM(Object Relation Mapping)模型将数据库存储数据与POJO对象进行映射,从而简化数据转化的复杂度;如果说Hibernate是完全封装的ORM框架,则myBatis则是半完全封装的ORM框架,因为myBatis需要手动映射SQL返回结果与POJO对象的映射;

java连接mysql一般有四种方式,不基于连接池的jdbc和基于连接池的dbcp, c3p0, jndi:
#1 jdbc:不使用连接池,每次进行DB操作都通过java.sql.DriverManager.getConnection获取一个新的connection,并通过openSession()获取一个交互session;
#2 dbcp:基于org.apache.commons.dbcp.BasicDataSource并创建connection pool,BasicDataSourceFactory.createDataSource获取DBCP数据源,然后获取可重复使用的connection;
#3 c3p0:基于DataSource并创建connection pool,ComboPooledDataSource.getConnection获取可重复使用的connection。
#4 jndi:基于DataSource并创建connection pool,InitialContext.getConnection获取connection。

myBatis解决了原生JDBC访问DB的几大问题:

#1 DB Connection频繁的开启和关闭会造成资源的浪费,所以使用DB Connection Pool通过重复利用Connection可以极大降低DB资源的消耗;connection创建session并开启transaction,session结束后transaction也关闭,并将connection归还给pool;
#2 使用可配置的方式兼容多种DataSource(jndi, c3p0, dbcp)的连接池;
#3 越来越多的业务需要根据数据来动态生成sql语句,传统的preparedStatement都是基于固定的sql来填充参数,mybatis提供if-else等标签根据业务数据动态生成并组装sql;
#4 mybatis提供ResultMap等自动映射的方式对查询结果进行解析,并提供[sql + params]作为key的方式将查询结果进行缓存;
#5 mybatis提供<sql />标签将一些共用的sql片段抽取出来,供多个地方引用;

对比MyBatis和Hibernate

#1 myBatis中的SQL是在开发的时候就已经写好的,并且可以细粒度的优化SQL语句,hibernate则是完全根据Object生成SQL,性能上会有一些影响;但同时hibernate的DB关联性低,可移植性高,myBatis由于定制化了大量的SQL,则在迁移DB的时候需要考虑兼容性;

Mybatis可接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发;但缺点是mybatis无法做到数据库无关性,如果需要实现支持多种数据库则需要自定义多套sql映射文件,myBatis同样支持通过java bean定义逆向生成CRUD操作对应的SQL。

#2 Hibernate提供的是一种全表映射的模型,因此在做关联查询的时候hibernate会将相关表的所有字段都加载到内存,然后再将数据封装成需要的对象;而myBatis会根据resultMap仅仅将需要的数据加载到内存,并自动转化成需要的对象,可以极大提升效率。

#3 Hibernate有一整套DAO对象的状态管理机制,myBatis则没有完整的DAO管理机制,需要手动维护DAO对象的数据更新操作;

#4 Hibernate的ORM映射关系是固定的,如果某些字段或者某些查询条件需要动态生成则只能通过HQL实现(性能较差),而myBatis天然支持SQL的动态生成,可以支持table名字或者column名字动态变化的场景;

#5 Hibernate不能有效支持存储过程,myBatis天然支持存储过程,store procedure的优势在于将业务逻辑封装到DB端,更安全稳定、执行性能也高,但劣势在于bug tracking和可移植性;

在spring中集成myBatis

首先在spring配置文件service.xml中配置 DBCP数据源,TxManager 和SqlSession的封装。

 

 1 <beans xmlns="http://www.springframework.org/schema/beans">
 2   <bean id="dbcpDataSource"
 3     class="org.apache.commons.dbcp.BasicDataSource">
 4     <property name="driverClassName">
 5       <value>com.mysql.jdbc.Driver</value>
 6     </property>
 7     <property name="url">
 8       <value>jdbc:mysql://localhost:3306/ychenDemo</value>
 9     </property>
10     <property name="username">
11       <value>root</value>
12     </property>
13     <property name="password">
14       <value>password</value>
15     </property>
16   </bean>
17 
18   <bean id="mybatisTxManager"
19     class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
20     <property name="dataSource" ref="dbcpDataSource" />
21   </bean>
22 
23   <bean id="sqlSessionFactory"
24     class="org.mybatis.spring.SqlSessionFactoryBean">
25     <property name="dataSource" ref="dbcpDataSource" />
26     <property name="configLocation"
27       value="mybatis/mybatis-config.xml"></property>
28   </bean>
29 
30   <bean id="myBatisBaseMapper"
31     class="org.mybatis.spring.mapper.MapperFactoryBean" abstract="true"
32     lazy-init="true">
33     <property name="sqlSessionFactory" ref="sqlSessionFactory" />
34   </bean>
35 
36   <bean id="userMapper" parent="myBatisBaseMapper">
37     <property name="mapperInterface"
38       value="ychen.demo_mybatis.mapper.UserMapper" />
39   </bean>
40 
41   <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
42     <constructor-arg index="0" ref="sqlSessionFactory" />
43   </bean>
44 </beans>

mybatis提供两种DB操作的接口:
-1 通过sqlSessionTemplate提供统一接口,并在参数中指定statementID和parameterList的方式;

 1 public List<Person> getPersonById(Long personId) {
 2     Map<String, Long> params = Maps.newHashMap();
 3     params.put("personId", personId);
 4     List<Person> result = template.selectList("getPersonById", params);
 5     return result;
 6 }
 7 
 8 >>>>>>>>>>>>>
 9 <mapper namespace="personMapper">
10   <select id="getPersonById" resultType="com.ychen.Person">
11     SELECT * FROM person WHERE id = #{personId}
12   </select>
13 </mapper>

-2 通过定义mapper interface,并使用SqlSessionFactoryBean和MapperFactoryBean动态代理的方式生成mapper实现类,mapper interface中可以自定义多个DB访问接口,内部实现依旧是转换成sqlSessionTemplate统一接口的方式,只是封装性更好。

 1 @Component
 2 public interface UserMapper {
 3     void insert(UserEntity user);
 4     UserEntity getOne(Long id);
 5 }
 6 
 7 >>>>>>>>>
 8 <mapper namespace="ychen.demo_mybatis.mapper.UserMapper">
 9   <select id="getOne" parameterType="Long" resultMap="BaseResultMap">
10     SELECT  <include refid="Base_Column_List" />
11     FROM payment_session
12     WHERE id = #{id}
13   </select>
14 </mapper>
15 
16 >>>>>>>>>
17 UserMapper userMapper = 
18     applicationContext.getBean("userMapper", UserMapper.class);
19   UserEntity userEntity = userMapper.getOne(1L);

构建sqlSessionFactory所需的myBatis-config.xml配置

 1 <configuration>
 2   <!-- resource属性引入外部定义的key/value变量,也可通过property标签定义内部变量 -->
 3   <properties resource="org/mybatis/example/mybatis-config.properties"> 
 4     <property name="username" value="dev_user"/> 
 5     <property name="password" value="F2Fa3!33TYyg"/> 
 6   </properties>
 7   <!-- 定义mybatis的运行变量 -->
 8   <settings>
 9     <setting name="cacheEnabled" value="true"/>
10     <setting name="lazyLoadingEnabled" value="true"/>
11     <setting name="multipleResultSetsEnabled" value="true"/>
12     <setting name="useColumnLabel" value="true"/>
13     <setting name="useGeneratedKeys" value="false"/>
14     <setting name="autoMappingBehavior" value="PARTIAL"/>
15     <!-- SIMPLE|REUSE|BATCH -->
16     <setting name="defaultExecutorType" value="SIMPLE"/>
17     <setting name="defaultStatementTimeout" value="25"/>
18     <setting name="defaultFetchSize" value="100"/>
19     <setting name="safeRowBoundsEnabled" value="false"/>
20     <setting name="mapUnderscoreToCamelCase" value="false"/>
21     <setting name="localCacheScope" value="SESSION"/>
22     <setting name="jdbcTypeForNull" value="OTHER"/>
23     <setting name="lazyLoadTriggerMethods" 
24       value="equals,clone,hashCode,toString"/>
25   </settings>
26   <!-- 定义常用类型的简写别名,同时mybatis为java常用类型提供了缺省别名 -->
27   <typeAliases>
28     <typeAlias type="leo.chen.domain.UserAccount" alias="UserAccount" />
29     <typeAlias type="leo.chen.domain.SpecialCar" alias="SpecialCar" />
30   </typeAliases>
31   <!-- 处理参数和返回结果在java-type和db-type间的转换,同时myBatis提供常用类型的handler -->
32   <!-- 通过继承BaseTypeHandler类或者实现TypeHandler接口,可以定制化转换方法 -->
33   <typeHandlers>
34     <typeHandler handler="com.active.services.endurance.mybatis.UUIDTypeHandler" 
35       javaType="java.util.UUID" jdbcType="VARCHAR"/>
36   </typeHandlers>
37   <!-- myBatis创建结果对象实例时使用默认的工厂类实现,通过objectFactory可以替换默认的工厂 -->
38   <objectFactory type="leo.chen.manager.CustomizedObjectFactory">
39     <property name="property1" value="value1">
40   </objectFactory>
41   <!-- 用于对mybatis处理流程中某些方法的扩展处理,如缓存一致性,如分页 -->
42   <plugins>
43     <plugin interceptor="org.mybatis.example.validationPlugin"> 
44       <property name="isThrowExp" value="true"/> 
45     </plugin> 
46   </plugins>
47   <!-- 定义mybatis的执行环境,包括事务管理、数据源等配置 -->
48   <environments default="development">
49     <environment id="development"> 
50       <transactionManager type="JDBC"> </transactionManager> 
51       <dataSource type="POOLED"> 
52         <property name="driver" value="${driver}"/> 
53         <property name="url" value="${url}"/> 
54         <property name="username" value="${username}"/> 
55         <property name="password" value="${password}"/> 
56         <property name="defaultTransactionlsoltionLevel" value="${txLevel}"/>
57         <property name="poolMaximumActiveConnection" value="10"/>
58         <property name="poolMaximumldleConnection" value="10"/>
59         <property name="poolMaximumCheckoutTime" value="20000"/>
60         <property name="poolTimeToWait" value="20000"/>
61         <property name="poolPingQuery" value="NOPINGQUERYSET"/>
62         <property name="poolPingEnabled" value="false"/> 
63         <property name="poolPingConnectionsNotUsedFor" value="0"/> 
64       </dataSource> 
65     </environment>
66   </environments>
67   <!-- 数据库厂商标识 -->
68   <databaseIdProvider type=""></databaseIdProvider>
69   <!-- 定义mapper映射文件 -->
70   <mappers>
71     <mapper resource="mybatis/productMapper.xml" />
72   </mappers>
73 </configuration>

#1 mybatis提供两种事务管理配置,JDBC和MANAGED,前者使用正常的JDBC的事务管理,也就是对java.sql.Connection事务管理的封装,依赖于从data source获取的连接来管理实务;后者将事务管理交由WEB容器进行管理,也就是说调用ManagedTransaction的commit和rollback并不会有任何动作;如果myBatis跟spring集成,则不需要配置此项。

#2 mybatis提供三种数据源的的配置,POOLED, UNPOOLED和JNDI,POOLED是在UNPOOLED的封装上添加了connection缓存管理的实现,UNPOOLED的实现仅仅是打开和关闭连接;而JNDI则是通过jndi服务查找代理的data source实现;如果myBatis跟spring集成,则也不需要配置此项。

#3 localCacheScope表示设置一级缓存的使用范围,缺省为SESSION,如果设置为STATEMENT则表示一级缓存仅限于一次statement使用,也就是禁用缓存。鉴于mybatis一级缓存实现不完整,容易造成数据一致性问题,因此建议使用STATEMENT。

#4 <plugins>标签允许在mybatis内部的四个大的处理流程中插入自定义的处理方法:
-1 Executor:处理mybatis的整个流程和二级缓存的使用
-2 ParameterHandler:处理mybatis对sql传入参数的赋值,
-3 StatementHandler:处理mybatis与db进行交互的规则和一级缓存的修改,
-4 ResultSetHandler:处理mybatis对结果集的映射规则;
具体的实现类需要实现Interceptor接口及对应的方法。

1 public interface Interceptor {   
2    //通过invocation.getTarget()可以定制不同阶段的plugin
3    Object intercept(Invocation invocation) throws Throwable;       
4    Object plugin(Object target);    
5    void setProperties(Properties properties);
6 }