这段时间因为做一个应用的需要,重新捡起ibatis+spring做web开发。
用ibatis的原因是速度,hibernate的执行速度和执行过程中产生的海量的类文件加载卸载的垃圾太多了,需要设置很大的Permgen的大小,才能保证运行正常。
但是重新使用Ibatis的时候,发现Ibatis好多的方法都被@Deprecated的,看样子升级到mybatis势在必行。
升级过程主要包括几个方面
1,jar包升级。
需要引入mybatis的包,同时 引入mybatis和spring集成的包。还包括数据库的包,连接池的包,另外mybatis估计使用的是动态代理机制,所以需要引入cglib的包。
<!-- mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.2.5</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.1</version> </dependency> <!-- dbcp --> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <!--Mysql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.13</version><!--$NO-MVN-MAN-VER$ --> </dependency>
2,修改spring的配置方式
spring配置主要是配置数据源、配置SqlSessionFactoryBean和配置SqlSessionTemplate。SqlSessionTemplate是mybatis和ibatis的区别项,ibatis使用SqlMapClientDaoSupport作为应用调用ibatis的接口,mybatis升级使用了SqlSessionTemplate,因此配置的时候需要更改这个选项。
<!-- 数据源配置, 使用应用中的DBCP数据库连接池 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <!-- Connection Info --> <property name="driverClassName" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <!-- Connection Pooling Info --> <property name="maxActive" value="${dbcp.maxActive}" /> <property name="maxIdle" value="${dbcp.maxIdle}" /> <property name="defaultAutoCommit" value="true" /> <property name="timeBetweenEvictionRunsMillis" value="3600000" /> <property name="minEvictableIdleTimeMillis" value="3600000" /> </bean> <!-- iBatis --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="configLocation"> <value>classpath:sqlMapConfig.xml</value> </property> </bean> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg> </bean>
3,修改sqlMapConfig.xml的配置参数。
由于mybatis和ibatis配置方式区别很大,备注几点,1引入的dtd文件需要改,2,别名的配置必需在这个文件中,不能再每个映射文件里面分别配置3,配置文件使用mapper而不是sqlMap。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <!-- 这个配置使全局的映射器启用或禁用缓存 --> <setting name="cacheEnabled" value="true" /> <!-- 允许 JDBC 支持生成的键。需要适合的驱动。如果设置为 true 则这个设置强制生成的键被使用,尽管一些驱动拒绝兼容但仍然有效(比如 Derby) --> <setting name="useGeneratedKeys" value="true" /> <!-- 配置默认的执行器。SIMPLE 执行器没有什么特别之处。REUSE 执行器重用预处理语句。BATCH 执行器重用语句和批量更新 --> <setting name="defaultExecutorType" value="REUSE" /> <!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载。 --> <setting name="lazyLoadingEnabled" value="true" /> <!-- 设置超时时间,它决定驱动等待一个数据库响应的时间。 --> <setting name="defaultStatementTimeout" value="25000" /> </settings> <!-- 别名配置 --> <typeAliases> <typeAlias alias="Product" type="com.eelicai.po.Product" /> </typeAliases> <!-- 指定映射器路径 --> <mappers> <mapper resource="com/eelicai/dao/sql/ProductSQL.xml" /> </mappers> </configuration>
4,修改mapper文件。
这个修改的项比较多,可以参考http://www.myexception.cn/software-architecture-design/1165287.html
主要是
1,不要使用之前的动态SQL方式,比如isNotEmpty
2,变量的引用方式使用#{}
<?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="ProductSQL"> <select id="getProductList_sql" resultType="Product"> <![CDATA[ select * from product ]]> </select> <!--通过id获取resultPage记录 --> <select id="getProductById_sql" parameterType="long" resultType="Product"> <![CDATA[ select * from product where id=#{id} ]]> </select> <!--增加新的记录 --> <insert id="saveProduct_sql" parameterType="Product" useGeneratedKeys="true" keyProperty="id"> insert into product(name,introduction,url,dailyValue,avgValue) values (#{name},#{introduction},#{url},#{dailyValue},#{avgValue}) <selectKey resultType="long" keyProperty="id"> SELECT LAST_INSERT_ID() AS id </selectKey> </insert> <!--修改记录 --> <update id="updateProductById_sql" parameterType="Product"> update product set id=#{id} ,name=#{name} ,introduction=#{introduction} ,url=#{url} ,dailyValue=#{dailyValue} ,avgValue=#{avgValue} where id=#{id} </update> <!--删除记录 --> <delete id="delProductById_sql" parameterType="long"> delete from product where id=#{id} </delete> </mapper>
这儿需要标记一个小点,我需要实现一个保存之后可以返回ID的功能。按照之前的方式,根据save方法返回的数字可以得到这个ID,但是mybatis已经修改了这个功能,返回的是影响的条数而不是ID。mybatis的处理方式和hibernate比较像,直接把相应的值设定到对象中。
因此,着重标记几点
1),使用selectKey,其中有个order属性,可以使用before和after,用来标记前后,可以自己google这点。
<selectKey resultType="long" keyProperty="id"> SELECT LAST_INSERT_ID() AS id </selectKey>
2),mysql数据库使用@@identity 和LAST_INSERT_ID()都可以返回使用的ID。但是很容易想到的一个问题是关于并发的,如果说所有的应用都共享这个查询数据的话,那么高并发的时候,返回的ID就一定是不对的。
所以查了一下这个相关的问题,主要的回答有几个:
http://zhidao.baidu.com/link?url=3wZfO_VNtyb3rj-C_lSKUOLbC7hGHXC6JXRRF1EZBAv6mz5jxsRPMiuleV-Mi8p5m9GOiodrKrPamCEnFTse2a
http://forums.devshed.com/php-development-5/last_insert_id-deal-concurrency-545291.html
简单的说就是,LAST_INSERT_ID()这个函数是和连接绑定的,保证每个连接可以返回自身修改的数据,其它连接的修改提交是修改不了本连接返回的值的。
5,修改调用方式
@Resource private SqlSessionTemplate sqlSession;
6,其它特性
mybatis加了一些新的特性需要继续研究,下次在写
6.1 动态SQL的书写
参考http://haohaoxuexi.iteye.com/blog/1338557
大体的意思是使用OGNL标签(类似JSTL)去做相应的操作。所以猜测mybatis使用的是模板配置的方式,生成SQL语句,速度不知道怎么样。
6.2 加了一个叫映射器的新东西,只需要写出接口而不需要实现类就能够操作数据
That's All.
本文只是记录最近做的事情和一些经验所得,由于没有系统整理过,所以自己看懂就可以了。