(文章还没写完就出了趟远门,汗颜,先喘口气再接着写)
相比Hibernate,MyBatis是轻量级的持久化框架,各大互联网公司都在应用,面试时也都会闲扯上几句(虽然MyBatis源码很糙)。MyBatis的优势:消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索,使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs映射成数据库中的记录。
没有对比没有伤害
与Hibernate相比
1.开发难度低:Mybatis框架相对简单易掌握,
2.工作量:都有代码自动生成工具,工作量上大致差不多(需要特别注意的是针对高级查询,Mybatis需要手动编写SQL语句,对Coder掌握sql使用能力更高;Hibernate有良好的映射机制,更让人专注于业务,但是作为程序个人认为Mybatis更为灵活)
3.sql上:Hibernate的查询是将所有字段查出来(select * from ...),不能只查询其中一部分,如果数据量大,字段多,性能很低的;相对的,Mybatis更灵活,可以定制查询。
4.缓存方面(1级缓存,即本地缓存):Hibernate一级缓存是Session缓存,Hibernate二级缓存是SessionFactory级的缓存;MyBatis的缓存更为强大,默认情况下是session级别(使用事务的时候尤其要注意,尤其是Read commit事务级别,在一个线程中同一个sql查询在不同的方查询的结果是一样的,即使查询前更新了数据库),还有STATEMENT。缓存规则上有:LRU FIFO SOFT WEAK
<setting name="localCacheScope" value="STATEMENT"/> <cache eviction=”FIFO” flushInterval=”60000″ size=”512″ readOnly=”true”/>
当然Hibernate也很多有点:DAO层开发简单,数据库移植性很好(MyBatis移植上较差),二级缓存机制更强大,可以使用第三方缓存如ehcache
原理
MyBatis架构图:
主要有:提供外部使用的API层;SQL查找、解析、执行、结果映射的数据处理层;负责最基础的功能(包括连接管理、事务管理、配置加载和缓存处理)支撑的数据支撑层。
流程
MyBatis处理流程如下:每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心的,SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得,而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先定制的 Configuration 的实例构建出 SqlSessionFactory 的实例。流程如图:
构造SqlSessionFactoryBuilder所需的Configuration
configuration 配置
* properties 属性
* settings 设置
* typeAliases 类型命名
* typeHandlers 类型处理器
* objectFactory 对象工厂
* plugins 插件
* environments 环境
* environment 环境变量
* transactionManager 事务管理器
* dataSource 数据源
* databaseIdProvider 数据库厂商标识
* mappers 映射器
SqlSessionFactoryBuilder通常的做法是创建一个全局的对象就可以了。
private static SqlSessionFactoryBuilder sqlSessionFactoryBuilder;
private static SqlSessionFactory sqlSessionFactory;
private static void init() throws IOException {
String resource = "mybatis-config.xml";
Reader reader = Resources.getResourceAsReader(resource);
sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
sqlSessionFactory = sqlSessionFactoryBuilder.build(reader);
}
SqlSessionFactory:SqlSessionFactory对象由SqlSessionFactoryBuilder创建,主要功能是创建SqlSession对象。通常的做法是创建一个全局的对象就可以了。
代码提到的mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN" "http://ibatis.apache.org/dtd/ibatis-3-config.dtd"> <configuration> <settings> <!-- 将下划线字段名称映射为驼峰变量 --> <setting name="mapUnderscoreToCamelCase" value="true"/> <!-- 进制mybatis进行延迟加载 --> <setting name="lazyLoadingEnabled" value="false"/> <!-- 本地缓存不使用session,使用STATEMENT --> <setting name="localCacheScope" value="STATEMENT"/> </settings> <plugins> <!-- 分页插件 --> <plugin interceptor="com.xxx.util.page.PagePlugin"> <property name="dialect" value="mysql"/> <property name="pageSql" value=".*ByPaging.*"/> </plugin> <!-- 调用链 --> <plugin interceptor="com.xxx.dtracker.mybatis.plugin.MapperInterceptor"></plugin> </plugins> <mappers> <mapper resource="mybatis/mapper/XXXConfigMapper.xml"/> <mapper resource="mybatis/mapper/XXXConfigMapper.xml"/> </mappers> <environments> //数据库链接信息,事务配置等 </environments> </configuration>
XXXConfigMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.xxx.PointTypeMapperExt"> <resultMap id="BaseResultMap" type="com.xxx.entity.PointType"> <id column="id" jdbcType="BIGINT" property="id" /> <result column="point_name" jdbcType="VARCHAR" property="pointName" /> <result column="data_type" jdbcType="BIT" property="dataType" /> <result column="remark" jdbcType="VARCHAR" property="remark" /> <result column="create_time" jdbcType="TIMESTAMP" property="createTime" /> <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" /> </resultMap> <sql id="Base_Column_List"> id, point_name, data_type, remark, create_time, update_time </sql> <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap"> select <include refid="Base_Column_List" /> from t_driver_score_point_type where id = #{id,jdbcType=BIGINT} </select> </mapper>
Spring中的实践
spring读取数据源spring-datasource.xml;
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:context="http://www.springframework.org/schema/context" xmlns:task="http://www.springframework.org/schema/task" xmlns:redis="http://zy.frame.redisclient/schema/redis" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd http://zy.frame.redisclient/schema/redis http://zy.frame.redisclient/schema/redis/redis.xsd"> <context:property-placeholder location="classpath*:*.properties"/> <import resource="dubbo.xml"/> <import resource="spring-mvc.xml"/> <import resource="spring-datasource.xml"/> <redis:client id="redisclient" zkHost="${redis.zkhost}" namespace="${redis.namespace}" isha="false" timeout="2000"/> <!-- spring scanner 如果扫描到base-package及子包有@Component @Controller@Service等这些注解的类,则把这些类注册为bean--> <context:component-scan base-package="com.xxx.xxx.xxx"/> <task:annotation-driven/> </beans>
spring-datasource.xml文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <bean id="financeDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url"> <value><![CDATA[${jdbc.url}]]></value> </property> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="initialSize" value="${jdbc.initial.size}" /> <property name="minIdle" value="${jdbc.minIdle}" /> <property name="maxActive" value="${jdbc.maxActive}" /> <property name="validationQuery" value="select 1" /> <property name="removeAbandoned" value="true"/> <property name="removeAbandonedTimeout" value="60"/> <property name="logAbandoned" value="true"/> <property name="connectionProperties" value="useUnicode=true;characterEncoding=utf8;connectTimeout=5000;socketTimeout=60000;autoReconnect=true;failOverReadOnly=false"/> </bean> <!--mybatis--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="configLocation"> <value>classpath:mybatis/mapper.xml</value> </property> <property name="dataSource" ref="financeDataSource" /> </bean> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg index="0" ref="sqlSessionFactory" /> </bean> <!-- 注解Mapper scanner --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!--扫描mapper文件--> <property name="basePackage" value="com.xxx.xx.**.dao" /> <property name="sqlSessionTemplateBeanName" value="sqlSession" /> </bean> <!-- 事务--> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="financeDataSource" /> </bean> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="txManager"/> </bean> <tx:annotation-driven transaction-manager="txManager" /> </beans>
mybatis/mapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN" "http://ibatis.apache.org/dtd/ibatis-3-config.dtd"> <configuration> <settings> <!-- 将下划线字段名称映射为驼峰变量 --> <setting name="mapUnderscoreToCamelCase" value="true"/> <!-- 进制mybatis进行延迟加载 --> <setting name="lazyLoadingEnabled" value="false"/> <!-- 不使用一级缓存 --> <setting name="localCacheScope" value="STATEMENT"/> </settings> <plugins> <plugin interceptor="com.xxx.xxx.xxx.util.page.PagePlugin"> <property name="dialect" value="mysql"/> <property name="pageSql" value=".*ByPaging.*"/> </plugin> <!-- 调用链 --> <plugin interceptor="com.xxx.dtracker.mybatis.plugin.MapperInterceptor"></plugin> </plugins> <mappers> <mapper resource="mybatis/mapper/XXXConfigMapper.xml"/> </mappers> </configuration>
XXXConfigMapper.xm见流程中的图
另外附上代码生成工具(命令:mvn mybatis-generator:generate):
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" > <generatorConfiguration > <context id="context1" > <commentGenerator> <property name="suppressDate" value="true" /> <property name="suppressAllComments" value="true" /> </commentGenerator> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://xxx:3189/dabaseName" userId="userName" password="password" /> <javaModelGenerator targetPackage="com.xxx.xxx.xxx.entity" targetProject="src/main/java"> <property name="enableSubPackages" value="true" /> <property name="trimStrings" value="true" /> </javaModelGenerator> <sqlMapGenerator targetPackage="mybatis/mapper" targetProject="src/main/resources"> <property name="enableSubPackages" value="true" /> </sqlMapGenerator> <javaClientGenerator type="XMLMAPPER" targetPackage="com.xxx.xxx.xxx.dao" targetProject="src/main/java"> <property name="enableSubPackages" value="true" /> </javaClientGenerator> <table tableName="XXXConfig" domainObjectName="XXXConfig" enableSelectByExample="false" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false"> </table> </context> </generatorConfiguration>