`
lovnet
  • 浏览: 6720737 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

ibatis 使用文档 (下篇)

 
阅读更多
====================================================================================
第5章 使用高级查询技术

一:用已映射语句关联对象


问题:如果你用过Hibernate或JPA,会想到entity(实体对象 -- 数据库对应JavaBean)之间可能存在关联关系。如一对一、多对多等。伴随就出现了关联获取技术,我们iBATIS如何做到关联获取呢?

使用iBATIS可以根据相关联的对象来定义数据模型,并且让iBATIS立即加载到它们。
例如:
假设你有一个数据库,其中Account记录和Order记录存在关联,建立起这些关联关系之后,请求Account记录时,就会同时获得所有关联的Order对象。

使用起来非常简单,大体通过以下步骤:
第一步:在我们的JavaBean中建立对应关系
public class Order implements Serializable {
	private static final long serialVersionUID = -7307764485708148107L;


	private Integer orderId;
	private String orderAddress;
...


public class Account implements Serializable {
	private static final long serialVersionUID = 3337778507086494766L;


	private Integer accountId;
	private String username;
	//建立了一个包含关联关系
	private List<Order> orders = new LinkedList<Order>();
...



第二步:创建表(我用的MySQL)
CREATE TABLE `orders` (
  `order_id` int(11) NOT NULL AUTO_INCREMENT,
  `order_address` varchar(20) DEFAULT NULL,
  `account_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`order_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;


CREATE TABLE `account` (
  `account_id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`account_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;


INSERT INTO `account` (`account_id`, `username`) VALUES 
  (1, 'hello'),
  (2, 'world');


INSERT INTO `orders` (`order_id`, `order_address`, `account_id`) VALUES 
  (1, 'hello1', 1),
  (2, 'hello2', 1);


第三步:在SqlMap中(Account.xml中)添加关联获取关系
主要在resultMap中做了手脚,实现方式很简单:
1.书写,我们关联获取时被调用的用于获取关联数据的<select>;被调取的用于获取关联数据的select中(也就是getOrderList中)参数使用#value#(固定格式)。
2.包含关联关系的resultMap标签中,除了添加自己本身表中对应的result,额外添加对应关联属性的result标签。
3.对应关联属性的result标签中,select属性值为被调取的用于获取关联数据的select标签的id。
4.对应关联属性的result标签中,column属性值为代码调取获取数据的<select>中“主表”的关联字段名称。
(<result property="orders" column="account_id" select="getOrderList" />)

<sqlMap namespace="Account">
	<typeAlias alias="account" type="com.partner4java.demo1.bean.Account" />
	<typeAlias alias="order" type="com.partner4java.demo1.bean.Order" />


	<!-- 简单关联方案 -->
	<resultMap class="account" id="accountMap">
		<result property="accountId" column="account_id" />
		<result property="username" column="username" />
		<!-- 通过select来获取的值放入orders;select需要一个关联参数,为本处column -->
		<result property="orders" column="account_id" select="getOrderList" />
	</resultMap>


	<resultMap class="order" id="orderMap">
		<result property="orderId" column="order_id" />
		<result property="orderAddress" column="order_address" />
	</resultMap>


	<select id="getAccount" resultMap="accountMap">
		select * from account
	</select>


	<select id="getOrderList" resultMap="orderMap">
		select * from orders where
		account_id = #value#
	</select>
</sqlMap>


第四步:执行代码
public static void main(String[] args) throws Exception {
	Reader reader = Resources.getResourceAsReader("sql-map-config.xml");
	SqlMapClient sqlMapClient = SqlMapClientBuilder
			.buildSqlMapClient(reader);
	List<Account> accounts = sqlMapClient.queryForList("getAccount", null);
	for(Account account:accounts){
		System.out.println(account);
	}
}
打印:
Account [accountId=1, username=hello, orders=[Order [orderId=1, orderAddress=hello1], Order [orderId=2, orderAddress=hello2]]]
Account [accountId=2, username=world, orders=[]]

延迟加载:
要使用延迟加载,需要编辑SqlMapConfig.xml文件,通过在<setting>元素中将lazyLoadingEnabled属性改为true来启动它。
如果想要使用延迟加载的cglib增强版,则必须下载并将其添加到应用程序的类路径中,同时也必须将<setting>元素中的enhancementEnabled属性改为true。
必须注意的是,这是一个全局设置,因此如果启用了这些特性,SQL映射中所有的已映射语句都将会使用延迟加载。

问题:你是否会揣摩到上面的查询方式会出现“N+1”问题呢,那么如何解决“N+1”问题?
避免N+1问题:
<!-- N + 1查询方案,注意每个resultMap都添加了一个groupBy -->
<resultMap class="order" id="orderJMap" groupBy="orders.order_id">
	<result property="orderId" column="order_id" />
	<result property="orderAddress" column="order_address" />
</resultMap>


<resultMap class="account" id="accountJMap" groupBy="account.account_id">
	<result property="accountId" column="account_id" />
	<result property="username" column="username" />
	<!-- 这里的resultMap为我们上面对order的定义 -->
	<result property="orders" resultMap="Account.orderJMap" />
</resultMap>


<select id="getAccountJ" resultMap="accountJMap">
	select
	account.account_id,account.username,orders.order_id,orders.order_address
	from account join orders on account.account_id = orders.account_id
	order
	by account.account_id,orders.order_id
</select>

public static void main(String[] args) throws Exception {
	Reader reader = Resources.getResourceAsReader("sql-map-config.xml");
	SqlMapClient sqlMapClient = SqlMapClientBuilder
			.buildSqlMapClient(reader);
	List<Account> accounts = sqlMapClient.queryForList("getAccountJ", null);
	for(Account account:accounts){
		System.out.println(account);
	}
}

但是这种方式会丢失不存在order的Account,可以使用left join。


问题:当我执行的不是一个简单insert、update时如何选择标签?
iBATIS框架的设计意图就是要灵活。当无法使用其他类型的已映射语句时,也许就可以使用<statement>已映射语句。
1.使用语句类型和DDL
<statement>类型的已映射语句有点奇怪,它和其他类型(例如<insert>)的已映射语句不同的地方就是,它没有对应的方法可以调用。
这就暗示了,我们不鼓励使用<statement>类型的已映射语句,只有在别无选择的情况下才可以考虑使用它。

<statement id="dropTableTest">
drop table test;
</statement>

sqlMapClient.update("dropTableTest", null);


==================================================================================================
第6章 事务

一:事务是什么


用最简单的话来说,事务就是一项通常包含若干步骤的工作单元,这些步骤必须作为整体来执行,无论成功还是失败。
也就是说,如果一个事务中的任何一个步骤失败了,那么所有其他步骤必须回滚,以保证数据仍处于一致的状态。

示例:就是常用的两个账户的转账的问题。

支持事务的数据库需要具备的特性通常称为ACID:原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability)。


二:自动事务


与JDBC还有所谓的“自动提交”模式不同,iBATIS处理的只有事务,它根本就没有在一个事务之工作的概念(除非你数据库不支持事务),因此它对“自动提交”的支持其实完全是间接的。
作为“自动提交”的替代,iBATIS支持所有的自动事务。
自动事务允许使用单个的方法调用来运行单个更新语句活查询语句,而完全不用关心如何划分事务。


三:局部事务
所谓局部事务,它仅仅涉及一个应用程序、一种资源(例如关系数据库),并且一次只能处理一个事务。

首先配置:
<transactionManager type="JDBC">
	<!-- SIMPLE是一个iBATIS内置事务管理器的名字 -->
	<dataSource type="SIMPLE">
...

public static void main(String[] args) throws Exception {
	Reader reader = Resources.getResourceAsReader("sql-map-config.xml");
	SqlMapClient sqlMapClient = SqlMapClientBuilder
			.buildSqlMapClient(reader);
	
	//学过jdbc的,是不是很容易理解啊?
	sqlMapClient.startTransaction();
	
	long being = System.currentTimeMillis();
	try {
		sqlMapClient.startBatch();
		for(int i=0;i<1000;i++){
			Account account = new Account("en5" + i, "o5", "EMPLOYEE");
			sqlMapClient.insert("insertAccount", account);
		}
		sqlMapClient.executeBatch();
		sqlMapClient.commitTransaction();
	} catch (Exception e) {
		e.printStackTrace();
	}finally{
		sqlMapClient.endTransaction();
	}
	System.out.println("time:" + (System.currentTimeMillis() - being));
	
}

定制事务:
我们也可以获取一个conn,然后使用conn手工管理事务,不过我们建议在基于conn管理事务的基础上使用sqlMapClient来执行SQL操作。
public static void main(String[] args) throws Exception {
	Reader reader = Resources.getResourceAsReader("sql-map-config.xml");
	SqlMapClient sqlMapClient = SqlMapClientBuilder.buildSqlMapClient(reader);
	Connection conn = null;
	SqlMapSession session = null;
	try {
		conn = sqlMapClient.getDataSource().getConnection();
		conn.setAutoCommit(false);
		session = sqlMapClient.openSession(conn);
		session.insert("insertAccount", new Account("hello", "123", "EMPLOYEE"));
		
		conn.commit();
	} catch (Exception e) {
		if(conn != null) conn.rollback();
		e.printStackTrace();
	}finally{
		if(session != null){
			session.close();
		}
		if(conn != null){
			conn.close();
		}
	}
}

(局部事务就不多说了,你自己打一遍就明白了)

==================================================================================================
第7章 使用动态SQL

一:先来个hello

<select id="queryAccount" resultClass="account" parameterClass="string">
	select * from user_account 
	<!-- 就多了一个这种标签,看这标签的起名是不是很像我们Junit里的断言啊? -->
	<isNotNull>
		where groupname = #value#
	</isNotNull>
</select>	

public static void main(String[] args) throws Exception {
	Reader reader = Resources.getResourceAsReader("sql-map-config.xml");
	SqlMapClient sqlMapClient = SqlMapClientBuilder
			.buildSqlMapClient(reader);
	List<Account> accounts = sqlMapClient
			.queryForList("queryAccount", "EMPLOYEE");
	for (Account account : accounts) {
		System.out.println(account);
	}
}


也可以:使用<dynamic>标签作为父标签
<dynamic>标签不像其他动态SQL标签,它不会去评测(evaluate)任何值或状态。它通常只是使用prepend属性,该属性值将作为前缀被加到<dynamic>标签的内容体之前。
如果<dynamic>标签的内容体经iBATIS处理后没有产生任何文本,那么prepend值将被忽略。
<select id="queryAccount" resultClass="account" parameterClass="string">
	select * from user_account 
	<dynamic>
		<isNotNull>
			where groupname = #value#
		</isNotNull>
	</dynamic>
</select>

二:熟悉动态标签

所有标签分为5类:
<dynamic>标签、二元标签、一元标签、参数标签以及<iterate>标签。

先看一下所有的动态SQL标签都有的属性和行为。
open、close:无条件地将其属性值放在标签的结果内容的开始处和结束处。
prepend:除了dynamic之外,prepend属性在所有其他标签中的功能也都是一样的。<dynamic>标签在内容体的结果SQL非空时,总是将其prepend属性值添加为该结果SQL的前缀。

只有当你想要向据诶过内容体使用open、close或prepend值时,才必须使用<dynamic>标签。


<dynamic>标签:
<dynamic>标签是最顶层标签;这意味着它不能被嵌套。该标签用来换分一个动态的SQL片段。
<dynamic>标签的属性:
prepend(可选的):该值用于作为前缀添加到标签的结果内容体前。但是当标签的结果内容体为空时,prepend值将不起作用。
open(可选的):该值用于作为前缀添加到标签的结果内容体前。但是如果结果内容体为空,open将不会附加到前面。open值将在prepend属性值被添加前缀先被添加前缀。
close(可选的):该值用于作为后缀附加到标签的结果内容体后。如果标签的结果内容体为空,close值将不起作用。

iBATIS二元标签:
二元标签(binary tag)用于将参数特性的某个值同另外一个值或者参数特性做比较。
如果比较结果为true,那么结果SQL中就包含其内容体。
所有的二元标签都共享compareProperty特性、compareValue属性。
property属性用于设置被比较的基本类型值,而compareProperty属性和compareValue属性则用于设置比较的参考值。
compareProperty属性会指定参数对象中的一个特性,该字段的取值会作为比较时的参数。
compareValue属性则会指定一个静态值,用于比较的基本类型值。
二元标签的属性:
property(必需的):参数对象中用于同compareProperty或者compareValue想比较的特性。
prepend(可选的):该值用于作为前缀附加到标签的结果内容体前。只有以下情况prepend值不会被加为前缀:当标签的结果内容体为空时;如果该标签是第一个产生内容体,且它被嵌套在一个removeFirstPrepend属性被设置为true的父标签中时。
open(可选的):该值用于作为前缀添加到标签的结果内容体前。如果标签的结果内容体为空,open值将不会被附加到其前面。open值将在prepend属性值被添加为前缀之前先被添加前缀。
close(可选的):该值用于作为后缀附加到标签结果内容体后。如果标签的结果内容体为空,则close值将不起作用。
removeFirstPrepend(可选的):该值用于确定第一个嵌套的内容生产标签是否移除其prepend值(prepend是可选属性)。
compareProperty(如果没有指定compareValue,则它是必需的):该值指定参数对象中的一个特性用来同property属性所指定的特性相比较。
compareValue(如果没有指定compareProperty,则它是必需的):该值指定一个静态比较值用于同property属性所指定的特性相比较。

二元动态标签:
<isEqual>:将property属性同compareProperty属性或compareValue属性相比较,确定他们是否相同。
<isNotEqual>:将property属性同compareProperty属性或compareValue属性相比较,确定他们是否不同。
<isGreaterThan>:确定property属性是否大于compareProperty属性或compareValue属性。
<isGreaterEqual>:确定property属性是否大于等于compareProperty属性或compareValue属性。
<isLessThan>:确定property属性是否小于compareProperty属性或compareValue属性。
<isLessEqual>:确定property属性是否小于等于compareProperty属性或compareValue属性。

iBATIS一元标签:
一元标签(unary tag)用于直接考察参数对象中某个bean特性的状态,而不是与其他进行比较。
如果参数对象的状态结果为真,那么结果SQL中就会包含其内容体。
所有的一元标签都共享property属性。一元标签的property属性用于指定参数对象上用来考察状态的特性。

一元标签属性:
property(必需的):参数对象中用于状态比较的特性。
prepend(可选的):该值用于作为前缀附加到标签的结果内容体前。只有以下情况prepend值不会被加为前缀:当标签的结果内容体为空时;如果该标签是第一个产生内容体,且它被嵌套在一个removeFirstPrepend属性被设置为true的父标签中时。
open(可选的):该值用于作为前缀,添加到结果内容体前。如果结果内容体为空,open值将不会被附加到其前面。open值将在prepend属性值被添加前缀之前先被添加前缀。
close(可选的):该值用于作为后缀附加到标签的结果内容体后。如果结果内容体为空,则close值将不起作用。
removeFirstPrepend(可选的):该属性值用于决定第一个产生内容的嵌套子标签是否移除其prepend值。

一元标签:
<isPropertyAvailable>:确定参数对象中是是否存在所指定的字段。对于bean,它寻找一个特性;而对于map,它寻找一个键。
<isNotPropertyAvailable>:确定参数中是否不存在所指定的字段。对于bean,它寻找一个特性;而对于map,它寻找一个键。
<isNull>:确定所指定的字段是否为空。对于bean,它寻找获取方法特性的返回值;而对于map,它寻找一个键,若这个键不存在,则返回true。
<isNotNull>:确定所指定的字段是否为非空。对于bean,它寻找获取方法特性的返回值;而对于map,它寻找一个键,若这个键不存在,则返回false。
<isEmpty>:确定所指定的字段是否为空、空字符串、空集合或者空的String.valueOf()。
<isNotEmpty>:确定所指定的字段是否为非空、非空字符串、非空集合或者非空的String.valueOf()。

iBATIS参数标签:
考虑到iBATIS允许定义没有参数的已映射语句。
参数标签(parameter tag)就是用来检查某个特定参数是否被传递给了已映射语句。
参数标签的属性和前面大同小异。
<isParameterPresent>:确定参数对象是否出现。
<isNotParameterPresent>:确定参数对象是否不存在。

iBATIS<iterate>标签:
<iterate>标签以一个集合或数组类型的特性作为其property属性值,iBATIS通过遍历这个集合(数组)来从一组值中重复产生某种SQL小片段。
这些小片段以conjunction属性值作为分隔符连接起来,从而形成一个有意义的SQL语句片段,open属性值将作为所呈现的值列表的前缀,close属性值将作为所呈现的值列表的后缀,最终形体形成一个完成合法的SQL。
<iterate>标签属性:
conjunction(可选的):该值用于连接iBATIS遍历集合(数组)时重复产生那些SQL小片段。
其它属性基本一致。

==================================================================================================
第8章 使用高速缓存提高性能

(导读:建议你看的同事自己动手练,有什么疑问自己用各种方式试出来)
(测试的建议:想看下是不是缓存,可在两次查询中做一个线程等待,然后去修改数据库,等待结束后,看数据是否改变,当然前提是你的缓存时间长于你的两次打印时间间隔,且修改工作在等待过程中完成)

一:一个简单的iBATIS高速缓存示例

iBATIS的强健且简单的高速缓存机制是完全基于配置的,因此避免了直接使用高速缓存的负担。
<!-- type="MEMORY",指定其高速缓存类型为MEMORY,把查询结果直接存储在内存中。 -->
<cacheModel type="MEMORY" id="categoryCache">
	<!-- flushOnExecute标签用于指定当某个特定高速缓存被访问时,其存储结果将被清除。 -->
	<flushOnExecute statement="insert" />
	<flushOnExecute statement="update" />
	<flushOnExecute statement="delete" />
	<!-- 每一种类型的高速缓存模型都有一些专用于它自己配置的特性,property标签就是用于完成这些专用特性的设置的。那么属性指定该高速缓存模型将要设置的特性的名称,value指定该预定义特性的值。 -->
	<property name="reference-type" value="WEAK" />
</cacheModel>


<select id="queryAccount" resultClass="account" parameterClass="string"
	cacheModel="categoryCache">
	select * from user_account
	<dynamic>
		<isNotEmpty>
			where groupname = #value#
		</isNotEmpty>
	</dynamic>
</select>

二:理解高速缓存模型

有关高速缓存模型,最简单的描述就是,它是一种高速缓存配置。或者更确切的说,它是定义所有的iBATIS高速缓存实现的基础。
高速缓存模型的配置是在SQL Map配置文件中,通过<cacheModel>标签来定义。
<cacheModel>标签属性:
id(必需的):该值用于指定一个唯一的ID,便于为需要使用此高速缓存模型所配置的高速缓存的查询已映射语句所引用。
Type(必需的):此属性用于指定高数缓存模型所配置的高速缓存的类型。其有效值包括MEMORY、LRU、FIFO和OSCACHE。该属性也可取值为某个自定义CacheController实现的全限定类名。
readOnly(可选的):将该值设置为true,就表示高速缓存将仅仅被用作只读高速缓存。
serialize(可选的):该属性值指定在读取高速缓存内容时是否要进行“深复制”

1.type属性 -- 内置的各种高速缓存模型类型:
MEMORY:这个模型简单的将高速缓存保存在内存中,直至垃圾收集器将它移除。
FIFO:这个模型中,高速缓存的数据量是固定的,使用“先进先出(first in first out)”算法来移除高速缓存中的数据。
LRU:这个模型中,高速缓存的数据量也是固定的,使用“最近最少使用(least recently used)”算法来移除高速缓存中的数据。
OSCACHE:这个模型使用OpenSymphony高速缓存

要使用何种高速缓存实现,是通过将它们相应的默认关键字(MEMORY、LRU、FIFO以及OSCACHE)添加到<cacheModel>标签的type属性来指定的。
也可以自己实现CacheController接口,然后在type属性中指定其全限定类名,以提供一套自己的高速缓存方案。

2.readOnly属性:
<cacheModel>标签提供了一个readOnly属性。
该属性仅仅是一个为高速缓存模型提供指令的指示器,用于告诉高速缓存模型应该如何检索和保存已告诉缓存对象。
该属性设置为true,并不能保证从高速缓存中检索出的对象其内容不被改变。
指定一个高速缓存为只读时,也就是告诉高速缓存模型允许其返回对存在于高速缓存中的某个对象的引用,因为该对象将不会被正在请求它的应用程序所改变。
如果readOnly属性设置为false,就可以确保不会出现多个用户同时访问某个已高速缓存的对象的同一引用实例的情况。

3.serialize属性:
serialize属性用于指示已高速缓存对象应该如何返回。
当该属性被设置为true时,高速缓存中所请求的每个对象都将作为一个深拷贝被返回。
这就意味着从高速缓存中检索出来的对象只具有相同的值,但并不是同一个实例。
这就可以确保存储在高速缓存中的实际数据永远不会被改变。
需要注意的是,此处所谓的串行化并不是我们所学的“序列化”,它并不是把数据串行化到硬盘上。
这里的串行化是基于内存的串行化,用于创建内存中已高速缓存对象的深拷贝。

4.联合使用readOnly属性和serialize属性:
它们看上去在功能上视乎存在一些重叠,事实上,它们需要紧密协同才能正常工作。
readOnly serialize结果 原因
true false 可以最快速的检索出已高速缓存的对象。返回已高速缓存对象的一个共享实例,若使用不当可能会导致问题。
false true 能快速检索出已高速缓存对象。返回已高速缓存对象的一个深拷贝。
false false 警告 对于此种组合,高速缓存仅仅对调用线程的会话的声明周期有关,且不能被其他线程所使用。
true true 这种组合同readOnly=false而serialize=true的组合作用一致,否则它在语义上没有任何意义。

以上两个属性的默认组合是readOnly=true和serizalize=false。


三:如何使用高速缓存模型中的标签
1.高速缓存的清除
<flushOnExecute> -- 定义查询已映射语句,其执行将引起相关高速缓存的清除
<flushInterval> -- 定义一个时间间隔,高速缓存将以此间隔定期清除

<flushOnExecute>标签:
只有一个属性statement,当某条已映射语句执行时,将触发相应高速缓存的清除。
当你在需要必须更新高速缓存以保证与数据库一致是尤其有用。

<flushInterval>标签:
除了时间之外它没有任何配置上的依赖性。
每个一定的时间间隔就会清除一次高速缓存。

2.设置高速缓存模型实现的特性:
<property>标签的属性name和value,都是必需的。
它们用来构建一个可传递给高速缓存模型组件以供其初始化的Properties对象。

四:高速缓存模型的类型
MEMORY:
MEMORY高速缓存是一种基于引用的高速缓存。
高速缓存中的每个对象都赋予一个引用类型。此引用类型为垃圾收集器提供了线索,指导它如何处理相应的对象。
引用类型:
WEAK -- 将很快的废弃高速缓存的对象。这种引用不会阻止对象被垃圾收集器收集。它仅仅提供一种方式来访问高速缓存中的对象,该对象在垃圾收集器的第一遍收集中就会被移除。(默认)如果因为某种原因GC比较频繁,那么会带来频繁访问数据库的问题。
SOFT -- 除非确定需要更多的内存,否则垃圾收集器始终不会收集对象。SOFT引用也确保不会超过内存限制,和WEAK相比,其数据库访问频率会低些。
STRONG -- 其中的已高速缓存对象永远不会被废弃,除非到达了指定清除时间间隔。
通过<property name="reference-type" value="WEAK" />来指定期望使用的引用类型。

LRU:
使用最近最少使用策略来管理高速缓存。
只有当高速缓存超过指定大小限制约束条件时,才会废弃最近最少被访问的对象。
大小限制定义了高速缓存中可以包含的对象数目。
<property name="size" value="200" />

FIFO:
才用先进先出的管理策略。
用法和收集点同上。
(<property name="size" value="200" />)

OSCACHE:
需要依赖OSCache的jar。并放入OSCache需要的配置文件。

==================================================================================================
第9章 结合Spring

先从配置文件下手,然后书写我们的service,最后调用测试

创建工程,我们Maven配置如下:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.partner4java.spring</groupId>
	<artifactId>5spring</artifactId>
	<version>0.0.1-SNAPSHOT</version>


	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<spring.version>3.1.1.RELEASE</spring.version>
		<ibatis.version>2.1.7.597</ibatis.version>
	</properties>


	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${spring.version}</version>
		</dependency>


		<dependency>
			<groupId>org.apache.ibatis</groupId>
			<artifactId>ibatis-sqlmap</artifactId>
			<version>2.3.4.726</version>
		</dependency>
		<dependency>
			<groupId>org.apache.ibatis</groupId>
			<artifactId>ibatis-core</artifactId>
			<version>3.0</version>
		</dependency>


		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.21</version>
		</dependency>
		<dependency>
			<groupId>c3p0</groupId>
			<artifactId>c3p0</artifactId>
			<version>0.9.1.2</version>
		</dependency>


		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib</artifactId>
			<version>2.2.2</version>
		</dependency>


		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.6.9</version>
		</dependency>


		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.10</version>
			<scope>test</scope>
		</dependency>
	</dependencies>


</project>

第一步:创建数据库相关配置文件

在类路径下创建:jdbc-c3p0.properties
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql://localhost:3306/ibatis_test?useUnicode=true&characterEncoding=UTF-8
user=root
password=123456


#初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3
initialPoolSize=1


#连接池中保留的最小连接数
minPoolSize=1


#连接池中保留的最大连接数。Default: 15
maxPoolSize=300


#最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0
maxIdleTime=60


#当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3
acquireIncrement=5


#每60秒检查所有连接池中的空闲连接。Default: 0
idleConnectionTestPeriod=120


#定义在从数据库获取新连接失败后重复尝试的次数。Default: 30
#acquireRetryAttempts=30


#两次连接中间隔时间,单位毫秒。Default: 1000
#acquireRetryDelay=1000


#连接关闭时默认将所有未提交的操作回滚。Default: false
#autoCommitOnClose=false


#JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 
#  属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。 
#  如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0
#maxStatements=100


#maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0 
#maxStatementsPerConnection=


#c3p0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能 
# 通过多线程实现多个操作同时被执行。Default: 3
#numHelperThreads=3


#当用户调用getConnection()时使root用户成为去获取连接的用户。主要用于连接池连接非c3p0 
#  的数据源时。Default: null
#overrideDefaultUser=root


#与overrideDefaultUser参数对应使用的一个参数。Default: null
#overrideDefaultPassword=


#定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。注意: 
#  测试的表必须在初始数据源的时候就存在。Default: null
#preferredTestQuery=select id from test where id=1


#用户修改系统配置参数执行前最多等待300秒。Default: 300
#propertyCycle=300


#因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的 
#  时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable 
#  等方法来提升连接测试的性能。Default: false
#testConnectionOnCheckout=false


#如果设为true那么在取得连接的同时将校验连接的有效性。Default: false
#testConnectionOnCheckin=true


#c3p0将建一张名为Test的空表,并使用其自带的查询语句进行测试。如果定义了这个参数那么 
#属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作,它将只供c3p0测试 
#使用。Default: null
#automaticTestTable=Test


#获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 
#  保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试 
#  获取连接失败后该数据源将申明已断开并永久关闭。Default: false
#breakAfterAcquireFailure=false


#当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出 
#  SQLException,如设为0则无限期等待。单位毫秒。Default: 0
#checkoutTimeout=5000


#通过实现ConnectionTester或QueryConnectionTester的类来测试连接。类名需制定全路径。 
#  Default: com.mchange.v2.c3p0.impl.DefaultConnectionTester
#connectionTesterClassName=


#指定c3p0 libraries的路径,如果(通常都是这样)在本地即可获得那么无需设置,默认null即可 
#  Default: null
#factoryClassLocation=


#maxConnectionAge=400

第二步:创建我们Spring的DataSource(不多说,不懂去查阅Spring相关资料)

创建文件datasource-c3p0.xml,放入类路径下的META-INF/spring中
<?xml version="1.0" encoding="GBK"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
	
	<context:property-placeholder location="classpath:jdbc-c3p0.properties" />
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
		<property name="driverClass" value="${driverClass}"/>
		<property name="jdbcUrl" value="${jdbcUrl}"/>
		<property name="user" value="${user}"/>
		<property name="password" value="${password}"/>
		<property name="initialPoolSize" value="${initialPoolSize}"/>
		<property name="minPoolSize" value="${minPoolSize}"/>	
		<property name="maxPoolSize" value="${maxPoolSize}"/>
		<property name="maxIdleTime" value="${maxIdleTime}"/>	
		<property name="acquireIncrement" value="${acquireIncrement}"/>	
		<property name="idleConnectionTestPeriod" value="${idleConnectionTestPeriod}"/>
	</bean>
	
	
</beans>

第三步:创建我们的JavaBean
public class Account implements Serializable {
	private static final long serialVersionUID = -6876471972027832806L;
	private int userid;
	private String username;
	private String password;
	private String groupname;
...

第四步:创建SqlMap
创建文件Account.xml放入类路径下的ibatis文件夹中
<?xml version="1.0" encoding="UTF-8" ?>


<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
    "http://ibatis.apache.org/dtd/sql-map-2.dtd">


<sqlMap namespace="Account">
	<typeAlias alias="account" type="com.partner4java.demo.entity.Account" />


	<select id="queryAccount" resultClass="account" parameterClass="string">
		select * from user_account
		<dynamic>
			<isNotEmpty>
				where groupname = #value#
			</isNotEmpty>
		</dynamic>
		order by userid desc
	</select>


	<insert id="insertAccount" parameterClass="account">
		insert into
		user_account(username,password,groupname)
		values(#username#,#password#,#groupname#)
	</insert>
</sqlMap>

第五步:创建我们iBATIS的sql-map-config.xml
创建文件sql-map-config.xml,放入类路径的ibatis文件中
<?xml version="1.0" encoding="UTF-8" ?>


<!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
    "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">


<sqlMapConfig>


    <settings 
	    useStatementNamespaces="true" 
	    />
	
	<sqlMap resource="ibatis/Account.xml" />
	
</sqlMapConfig>

第六步:继续配置Spring配置文件 -- 从Spring中创建SqlMapClient
创建文件beans.xml放入类路径下的META-INF/spring中
<?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:context="http://www.springframework.org/schema/context"
	xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:util="http://www.springframework.org/schema/util"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util-3.0.xsd">
	<aop:aspectj-autoproxy />
	<context:component-scan base-package="com.partner4java" />
	
	<import resource="classpath:META-INF/spring/datasource-c3p0.xml" />
	
	<!-- SqlMapClientFactoryBean是个Spring工厂Bean,用于生成SqlMapClient。
		iBATIS API的核心是SqlMapClient接口。
		SqlMapClient大致相当于Hibernate的Session或者JPA的EntityManager,用于执行全部的数据访问操作。 -->
	<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
		<property name="dataSource" ref="dataSource"/>
		<property name="configLocation" value="classpath:ibatis/sql-map-config.xml"/>
	</bean>
	
	<!-- SqlMapClientTemplate包裹了一个SqlMapClient来透明的打开和关闭会话,好捕获抛出的SQLException。 -->
	<bean id="sqlMapClientTemplate" class="org.springframework.orm.ibatis.SqlMapClientTemplate">
		<property name="sqlMapClient" ref="sqlMapClient"/>
	</bean>
		
</beans>        

第七步:创建我们的Service
public interface AccountService {
	List<Account> query(String groupname);
	void add(Account account);
}


@Service
public class AccountServiceBean implements AccountService {
	@Autowired
	private SqlMapClientTemplate sqlMapClientTemplate;
	public void setSqlMapClientTemplate(
			SqlMapClientTemplate sqlMapClientTemplate) {
		this.sqlMapClientTemplate = sqlMapClientTemplate;
	}


	public List<Account> query(String groupname) {
		return sqlMapClientTemplate.queryForList("Account.queryAccount",
				groupname);
	}


	public void add(Account account) {
		sqlMapClientTemplate.insert("Account.insertAccount", account);
	}


}

最后一步:测试
public class AccountServiceBeanTest {
	ApplicationContext applicationContext;
	private AccountService accountService;
	@Before
	public void setUp() throws Exception {
		applicationContext = new ClassPathXmlApplicationContext(
				"META-INF/spring/beans.xml");
		accountService = applicationContext.getBean("accountServiceBean", AccountService.class);
	}


	@Test
	public void testQuery() {
		System.out.println(accountService.query(null));
	}


}


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics