(10) ejb学习: Jpa的JTA事务和RESOURCE_LOCAL事务

一 事务的基本概念

   1 原子性 : 所有操作要么都成功,要么都失败

   2 一致性 : 事务不能违反完整性约束(比如虽然事务还未提交,但仍然需要遵守约束规则,这些规则是事务提交之前而

                    非事务提交之后才能生效)

   3 隔离性 : 一个事务的效果,不能影响其它同时执行的事务

   4 持久性 : 一旦事务成功完成,则数据必须保证已经正确的持久化


二 JDBC事务和JTA事务对比

 1  JDBC事务只能支持一个数据库(单数据源),而JTA可以支持分布式的事务(多数据源)

 2 JDBC事务,一般数据库本身来执行提交或者回滚操作(单阶段提交),所有数据库都有它自己的事务管理器,管理执行的

    日志,这些管理器只能处理自身的事务(称为本地事务)

 3 而JTA不同,JTA要支持多个数据源,站在更高的角度上,提供“事务处理监视器(TPM)”来管理和协调这些数据源之间的事务

    操作.它必须执行两个阶段的提交的(2PC)协议.

    3.1 准备阶段 : TPM向所有RM(资源管理器,即数据库)确认状态,是否可以提交或回滚。

    3.2 提交阶段 : TPM确认提交之后,向所有的RM发出提交指令(或回滚)

 4 TPM本身会维护事务日志,以保证持久性(灾难恢复等)


三 事务类型 ; JTA 和RESOURCE_LOCAL

  1 使用JAT来控制事务

     利用容器提供的JTA事务管理器来管理事务

   2 使用RESOURCE_LOCAL来控制事务

      可以脱离容器


四 案例

 1 项目结构图


Student.java : 学生实体类

StudentManager.java 学生管理接口类

StudentManagerImpl.java 学生管理实现类

JtaTest.java  Junit测试类,

               测试1 : testWithoutJta 没有JTA时候的效果

          测试2 : testJta  使用JTA时候的效果

               测试3testLocal 测试使用 RESOURCE_LOCAL 的效果

persistence.xml : 配置RESOURCE_LOCAL和JTA的数据源

jndi.properties : 配置JNDI

client : 为JtaTest中testWithoutJta 和 testJta  提供客户端环境

            jar包有 : JBOSS_HOME/client/*.jar

RESOURCE_LOCAL 为JtaTest中testLocal 提供环境

           jar包有 : JBOSS_HOME/server/default/lib/*.jar

                         JBOSS_HOME/lib/*.jar

五 代码

Student.java

package leaning;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Student {

	@Id
	@GeneratedValue
	private int id;

	private String name;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

}

StudentManager.java

package leaning;

public interface StudentManager {
   public void addStudent(String name);
}

StudentManagerImpl.java

package leaning;

import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless(name="studentManager")
@Remote
public class StudentManagerImpl implements StudentManager {
	
	@PersistenceContext(unitName="EjbLession11_JTA")
	private EntityManager em;

	public void addStudent(String name) {
		Student s = new Student();
		s.setName(name);
		em.persist(s);
		
	}

}

JtaTest.java

package test;

import static org.junit.Assert.*;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;

import leaning.Student;
import leaning.StudentManager;


import org.junit.Test;

public class JtaTest {

	/**
	 * 没有JTA测试
	 * 每调用studentManager.addStudent("张三"+i)就是一个事物
	 * 当i==5时候,抛出异常,因此有 张三0,张三1,张三2,张三3,张三4,张三5 这6个实体类被保存在数据库中
	 * **/
	@Test
	public void testWithoutJta() {
		 InitialContext context;
			try {
				context = new InitialContext();
				StudentManager studentManager = (StudentManager)context.lookup("studentManager/remote");
				for(int i =  0 ; i < 10 ; i++){
					studentManager.addStudent("张三"+i);
					if(i==5){
						throw new RuntimeException();
					}
				}
				
			} catch (NamingException e) {
			
				e.printStackTrace();
			}
	}

	/**
	 * JTA测试
	 * 与testWithoutJta代码基本一样,不同点在于开启了JTA事物,studentManager.addStudent("张三"+i) (i=0,1,2,3,4,5)都在一个事物中
	 * 发生throw new RuntimeException()后,事物回滚,因此没有插入任何数据
	 * **/
	@Test
	public void testJta() {
		InitialContext context;
		try {
			context = new InitialContext();
			
			//JTA事物管理接口
			UserTransaction utx = (UserTransaction)context.lookup("UserTransaction");
			
			StudentManager studentManager = (StudentManager)context.lookup("studentManager/remote");
			
			try{
				utx.begin(); //开启事物
				for(int i =  0 ; i < 10 ; i++){
					studentManager.addStudent("张三"+i);
					if(i==5){
						throw new RuntimeException();
					}
				}
				
				utx.commit(); //提交事物
				
			}catch(Exception e){
				try {
					utx.rollback(); //回滚
				} catch (Exception e1 ) {
					
					e1.printStackTrace();
				} 
				e.printStackTrace();
				
			}
			
		} catch (NamingException e) {
		
			e.printStackTrace();
		}
	}
	
	/**
	 * 测试本地容器事物
	 * **/
	
	@Test
	public void testLocal() {
		 EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("EjbLession11_RESOURCE_LOCAL");// 取 persistence.xml中 persistence-unit name="EjbLession11_RESOURCE_LOCAL" 
		 EntityManager em = entityManagerFactory.createEntityManager();
		 try{
			 em.getTransaction().begin();
			 Student student = new Student();
			 student.setName("李四");
			 em.persist(student);
			 em.getTransaction().commit();
		 }catch(Exception e){
			 em.getTransaction().rollback();
			 e.printStackTrace();
			 
		 }
	
	}
}

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
    http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
    
    <!-- 采集JTA事物 -->
	<persistence-unit name="EjbLession11_JTA" transaction-type="JTA">
  		<jta-data-source>java:/MySqlDS</jta-data-source>
  		<properties>
			<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
			<property name="hibernate.hbm2ddl.auto" value="update"/>
		</properties>
	</persistence-unit>
  
   <!-- 采用RESOURCE_LOCAL事物  -->
   <persistence-unit name="EjbLession11_RESOURCE_LOCAL" transaction-type="RESOURCE_LOCAL">
  		<provider>org.hibernate.ejb.HibernatePersistence</provider>
	    <properties>
			<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
		    <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/ejb" />
	        <property name="hibernate.connection.username" value="root" />
	        <property name="hibernate.connection.password" value="root" />
			<property name="hibernate.show_sql" value="true"/>
			<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
			<property name="hibernate.hbm2ddl.auto" value="update"/>
 	   </properties>
   </persistence-unit>
  
   
</persistence>

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=localhost
java.naming.factory.url.pkgs=org.jboss.naming\:org.jnp.interfaces


                  

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值