使用atomikos在spring3、jpa2/hibernate4中实现JTA

阅读更多

公司使用ssh框架,近期因为项目使用到多数据源,web服务器为tomcat,为了数据的一致性,需要使用jta。在spring中使用jta现有两个主要的开源项目:jotm、atomikos。spring3中己移除了对jotm支持,所以只能使用atomikos,按照网上资料学习,将实践过程记录下来,以备参考。
1、atomikos需要的jar

transactions-3.9.0.M1.jar
transactions-api-3.9.0.M1.jar
transactions-hibernate3-3.9.0.M1.jar
transactions-jta-3.9.0.M1.jar
transactions-jdbc-3.9.0.M1.jar
atomikos-util-3.9.0.M1.jar



2、persistence.xml



	
	
	
	
	


persistence.xml很简单,定义两个持久化单元,类型为JTA

3、application.properties

mysql.databasePlatform=org.hibernate.dialect.MySQL5InnoDBDialect
mysql.jdbc.driver=com.mysql.jdbc.Driver
mysql.jdbc.url=jdbc:mysql://localhost:3306/post?useUnicode=true&characterEncoding=utf-8
mysql.jdbc.username=root
mysql.jdbc.password=kfs

#Oracle
oracle.databasePlatform=org.hibernate.dialect.Oracle10gDialect
oracle.jdbc.driver=oracle.jdbc.driver.OracleDriver
oracle.jdbc.url=jdbc:oracle:thin:@127.0.0.1:1521:orcl
oracle.jdbc.username=test
oracle.jdbc.password=kfs



application.properties中配置两个数据,oralce和mysql

4、applicationContext.xml

	多数源JTA配置例子,本例子同时使用oracle、mysql数据同时提交、回滚事务

	
	
		
	

	

	
		
	

	
		
	

	
		
		
		
	

	
	

	
	


	
	
		
		
		
			
				${oracle.jdbc.username}
				${oracle.jdbc.password}
				${oracle.jdbc.url}
			
		
		
		
		
		
	
	
	

	
	
		
		
		
		
		
			
				true
				oracle.jdbc.xa.client.OracleXADataSource
				jta
				com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup
				
			
		
	

	
		
			${oracle.databasePlatform}
		
		
			true
		
		
			true
		
	


	
	


	
	
		
		
		
			
				${mysql.jdbc.username}
				${mysql.jdbc.password}
				${mysql.jdbc.url}
			
		
		
		
		
		
	

	
	
		
		
		
		
		
			
				true
				com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
				jta
				com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup
				
			
		
	

	
		
			${mysql.databasePlatform}
		
		
			true
		
		
			true
		
	


	
	



5、测试
oracle数据库实体类和dao类:

package com.techstar.topic.entity;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.hibernate.validator.constraints.NotBlank;

@Entity
@Table(name = "XA_TOPIC")
public class Topic {

        private String id;
	private String forumId;
	private String topicTitle;
	private String userId;
	private Date topicTime;
	private Integer topicViews;
	private Integer topicReplies;

	@Id	
	@GeneratedValue(generator = "system-uuid")// 主键自动生成策略:UUID
	@GenericGenerator(name = "system-uuid", strategy = "uuid")
	@Column(length=32)
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}

	@NotBlank
	@Column(length = 100)
	public String getForumId() {
		return forumId;
	}

	public void setForumId(String forumId) {
		this.forumId = forumId;
	}

	@NotBlank
	@Column(length = 200)
	public String getTopicTitle() {
		return topicTitle;
	}

	public void setTopicTitle(String topicTitle) {
		this.topicTitle = topicTitle;
	}

	@NotBlank
	@Column(length = 50)
	public String getUserId() {
		return userId;
	}

	public void setUserId(String userId) {
		this.userId = userId;
	}

	@Temporal(TemporalType.TIMESTAMP)
	public Date getTopicTime() {
		return topicTime;
	}

	public void setTopicTime(Date topicTime) {
		this.topicTime = topicTime;
	}

	public Integer getTopicViews() {
		return topicViews;
	}

	public void setTopicViews(Integer topicViews) {
		this.topicViews = topicViews;
	}

	public Integer getTopicReplies() {
		return topicReplies;
	}

	public void setTopicReplies(Integer topicReplies) {
		this.topicReplies = topicReplies;
	}

}



package com.techstar.topic.repository.jpa;

import org.springframework.data.jpa.repository.JpaRepository;

import com.techstar.topic.entity.Topic;

public interface TopicDao extends JpaRepository{

}


项目使用了spring data jpa,dao类很简单,定义接口即可。

mysql对应的实体类和dao类

package com.techstar.post.entity;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Lob;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.hibernate.validator.constraints.NotBlank;

@Entity
@Table(name = "XA_POST")
public class Post {

        private String id;
	private String topic;
	private String forumId;
	private String userId;
	private byte[] postAttach;
	private Date postTime;

	@Id	
	@GeneratedValue(generator = "system-uuid")// 主键自动生成策略:UUID
	@GenericGenerator(name = "system-uuid", strategy = "uuid")
	@Column(length=32)
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	@NotBlank
	@Column(name = "TOPIC", length = 32)
	public String getTopic() {
		return topic;
	}

	public void setTopic(String topic) {
		this.topic = topic;
	}

	@NotBlank
	@Column(length = 100)
	public String getForumId() {
		return forumId;
	}

	public void setForumId(String forumId) {
		this.forumId = forumId;
	}

	@NotBlank
	@Column(length = 50)
	public String getUserId() {
		return userId;
	}

	public void setUserId(String userId) {
		this.userId = userId;
	}

	@Lob
	public byte[] getPostAttach() {
		return postAttach;
	}

	public void setPostAttach(byte[] postAttach) {
		this.postAttach = postAttach;
	}

	@Temporal(TemporalType.TIMESTAMP)
	public Date getPostTime() {
		return postTime;
	}

	public void setPostTime(Date postTime) {
		this.postTime = postTime;
	}

}

 

package com.techstar.post.repository.jpa;

import org.springframework.data.jpa.repository.JpaRepository;

import com.techstar.post.entity.Post;

public interface PostDao extends JpaRepository{

}



junit单元测试类

package com.techstar.topic.service;

import java.util.Date;

import junit.framework.Assert;

import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;

import com.techstar.modules.utils.Identities;
import com.techstar.post.entity.Post;
import com.techstar.post.repository.jpa.PostDao;
import com.techstar.topic.entity.Topic;
import com.techstar.topic.repository.jpa.TopicDao;

@ContextConfiguration(locations = { "classpath:spring/applicationContext.xml" })
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
@Transactional
public class JTAServiceTest extends AbstractTransactionalJUnit4SpringContextTests {

	@Autowired
	private TopicDao topicDao;// oralce数据源
	@Autowired
	private PostDao postDao;// mysql数据源

	/**
	 * 单独俣存Topic到oracle数据库
	 */
	@Test
	public void saveTopic() {

		Topic topic = new Topic();
		topic.setForumId(Identities.uuid2());
		topic.setTopicReplies(5);
		topic.setTopicTime(new Date());
		topic.setTopicTitle(Identities.uuid2());
		topic.setTopicViews(2);
		topic.setUserId(Identities.uuid2());
		topicDao.save(topic);

		Assert.assertNotNull(topic.getId());
	}

	/**
	 * 单独俣存Post到mydql数据库
	 */
	@Test
	public void savePost() {

		Post post = new Post();
		post.setForumId(Identities.uuid2());
		post.setUserId(Identities.uuid2());
		post.setPostAttach(new String(Identities.uuid2()).getBytes());
		post.setPostTime(new Date());
		post.setTopic(Identities.uuid2());
		postDao.save(post);

		Assert.assertNotNull(post.getId());
	}

	/**
	 * 同时保存Topic到oracle数据库、Post到mydql数据库
	 */
	@Test
	public void saveTopicAndPostCommit() {

		Topic topic = new Topic();
		topic.setForumId(Identities.uuid2());
		topic.setTopicReplies(5);
		topic.setTopicTime(new Date());
		topic.setTopicTitle(Identities.uuid2());
		topic.setTopicViews(2);
		topic.setUserId(Identities.uuid2());
		topicDao.save(topic);

		Post post = new Post();
		post.setForumId(Identities.uuid2());
		post.setUserId(Identities.uuid2());
		post.setPostAttach(new String(Identities.uuid2()).getBytes());
		post.setPostTime(new Date());
		post.setTopic(topic.getId());
		postDao.save(post);

		Assert.assertNotNull(topic.getId());
		Assert.assertNotNull(post.getId());
	}

	/**
	 * Post回滚、Topic一起回滚
	 */
	@Test
	public void saveTopicAndPostRollback() {

		Topic topic = new Topic();
		topic.setForumId(Identities.uuid2());
		topic.setTopicReplies(5);
		topic.setTopicTime(new Date());
		topic.setTopicTitle(Identities.uuid2());
		topic.setTopicViews(2);
		topic.setUserId(Identities.uuid2());

		topicDao.save(topic);

		Post post = new Post();
		post.setForumId(null);// ForumId在数据设置不能为空,在这里设置为null,测试数据一起回滚
		post.setUserId(Identities.uuid2());
		post.setPostAttach(new String(Identities.uuid2()).getBytes());
		post.setPostTime(new Date());
		post.setTopic(topic.getId());

		postDao.save(post);

	}

	/**
	 * Topic回滚、Post一起回滚
	 */
	@Test(expected = ArithmeticException.class)
	public void saveTopicAndPostRollback2() {

		Post post = new Post();
		post.setForumId(Identities.uuid2());
		post.setUserId(Identities.uuid2());
		post.setPostAttach(new String(Identities.uuid2()).getBytes());
		post.setPostTime(new Date());
		post.setTopic(Identities.uuid2());

		postDao.save(post);

		Topic topic = new Topic();
		topic.setForumId(Identities.uuid2());
		topic.setTopicReplies(5);
		topic.setTopicTime(new Date());
		topic.setTopicTitle(Identities.uuid2());
		topic.setTopicViews(2);
		topic.setUserId(null);// UserId在数据设置不能为空,在这里设置为null,测试数据一起回滚

		topicDao.save(topic);

	}
}


最后运行单元测试,查看数据变化。

 

你可能感兴趣的:(jpa,spring,atomikos,jta,hibernate)