事务控制代码示例

如果不了解事务的概念的话,可参见笔者的另一篇文章"事务和MVCC" http://frank1234.iteye.com/blog/2164232

1 JDBC事务
这个没啥好说的,直接上代码
public class JdbcTransactionMain {
    public static void main(String[] args) throws Exception{
        Class.forName("com.mysql.jdbc.Driver");
        Connection conn = null;
        Statement st = null;
        try{
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/springdemo","root","frank1234");
            //开始事务
            conn.setAutoCommit(false);
            st = conn.createStatement();
            st.executeUpdate("insertsql1");
            st.executeUpdate("insertsql2");
            //事务提交
            conn.commit();
        }catch (Exception e){
            e.printStackTrace();
            //注意有异常必须得回滚,否则执行成功的sql会持久化到数据库中
            conn.rollback();
        }finally {//记得释放资源
            if(st != null)
                st.close();
            if(conn != null)
                conn.close();
        }
    }
}


2 Hibernate事务

public class HibernateTransactionMain {
    public static void main(String[] args) throws Exception{
        Session session = null;
        Transaction tx = null;
        try {
            session = new Configuration().configure().buildSessionFactory().openSession();
            //开始事务
            tx = session.beginTransaction();
            session.save(po1);
            session.save(po2);
            //提交事务
            tx.commit();
        }catch (Exception e){
            e.printStackTrace();
            //回滚事务
            tx.rollback();
        }finally {
            if(session != null)
                session.close();
        }
    }
}


3 Spring声明式事务
下面代码示例操作数据库使用Sping的JdbcTemplate
后台数据库表:
CREATE TABLE `person` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `sex` varchar(2) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=gb2312

CREATE TABLE `orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `cost` int(11) NOT NULL,
  `customerid` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=gb2312

Person对象
public class Person {

     /**
      * id号
      */
     private int id;
     /**
      * 姓名
      */
     private String name;
     /**
      * 年龄
      */
     private int age;
     /**
      * 性别
      */
     private String sex;


     public Person(int id, String name, int age, String sex) {
         this.id = id;
         this.name = name;
         this.age = age;
         this.sex = sex;
     }

     public Person() {
     }

     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;
     }

     public int getAge() {
         return age;
     }

     public void setAge(int age) {
         this.age = age;
     }

     public String getSex() {
         return sex;
     }

     public void setSex(String sex) {
         this.sex = sex;
     }

}

Order对象:
public class Order {
    private int id;
    private int cost;
    private int customerId;
    public int getId() {
        return id;
    }

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

    public int getCost() {
        return cost;
    }

    public void setCost(int cost) {
        this.cost = cost;
    }

    public int getCustomerId() {
        return customerId;
    }

    public void setCustomerId(int customerId) {
        this.customerId = customerId;
    }

    public String toString(){
        return "id="+id+",cost="+cost;
    }
}


TransactionDAO接口:
public interface TransactionDAO {
    public void savePersonAndOrder(Person person,Order order);
    public void savePerson(Person person);
    public void saveOrder(Order order);
}

TransactionDAOImpl实现类:
其中saveOrder()方法写错,让其操作不成功。
public class TransactionDAOImpl implements TransactionDAO{
    private JdbcTemplate jdbcTemplate;

    public void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    public void savePersonAndOrder(Person person,Order order) {
        savePerson(person);
        saveOrder(order);
    }

    public void savePerson(Person person) {
        jdbcTemplate.update("insert into person(name,age,sex)values(?,?,?)",
                new Object[] { person.getName(), person.getAge(),
                        person.getSex() }, new int[] { java.sql.Types.VARCHAR,
                        java.sql.Types.INTEGER, java.sql.Types.VARCHAR });

    }

    public void saveOrder(Order order) {
        jdbcTemplate.update("insert into order1(cost,customerid)values(?,?)",
                new Object[] { order.getCost(), order.getCustomerId()}, new int[] {
                        java.sql.Types.INTEGER, Types.INTEGER });
    }
}


Spring配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
        "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
    <!-- MySQL -->
    <bean id="dataSource"
       class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
       <property name="driverClassName" value="com.mysql.jdbc.Driver" />
       <property name="url" value="jdbc:mysql://localhost:3306/springdemo" />
       <property name="username" value="root" />
       <property name="password" value="frank1234" />
   </bean>


    <bean id="transactionDAO" class="org.frank1234.spring.transaction.TransactionDAOImpl">
        <property name="dataSource" ref="dataSource" />
    </bean>
   
</beans>


测试类:
public class TransactionMain {
    public static void main(String[] args) throws Exception{
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        TransactionDAO personService = (TransactionDAO) ctx.getBean("transactionDAO");

        Person person = new Person();
        person.setName("frank1234");
        person.setAge(21);
        person.setSex("男");
        // 保存一条记录


        Order order= new Order();
        order.setCost(10);
        order.setCustomerId(12);

        personService.savePersonAndOrder(person,order);


    }
}


执行后,数据库记录截图:



可见person表的记录还是写入了。


修改Spring配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
        "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
    <!-- MySQL -->
    <bean id="dataSource"
       class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
       <property name="driverClassName" value="com.mysql.jdbc.Driver" />
       <property name="url" value="jdbc:mysql://localhost:3306/springdemo" />
       <property name="username" value="root" />
       <property name="password" value="frank1234" />
   </bean>


    <bean id="transactionDAOTarget" class="org.frank1234.spring.transaction.TransactionDAOImpl">
        <property name="dataSource" ref="dataSource" />
    </bean>
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource">
            <ref bean="dataSource"/>
        </property>
    </bean>
    <bean id="transactionDAO" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="proxyInterfaces">
            <list>
                <value>org.frank1234.spring.transaction.TransactionDAO</value>
            </list>
        </property>
        <property name="target">
            <ref bean="transactionDAOTarget"/>
        </property>
        <property name="transactionManager">
            <ref bean="transactionManager"/>
        </property>
        <property name="transactionAttributeSource">
            <ref bean="transactionAttributeSource"/>
        </property>
    </bean>
    <bean id="transactionAttributeSource" class="org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource">

    </bean>
</beans>



清空数据库表记录,重新执行TransactionMain测试类。
数据库记录截图:



可见person没有写入,写入person和写入order是同一个事务了。

这就是Spring声明式事务,其本质是AOP,将事务相关的代码作为切面织入了目标对象的方法中。

4 JTA事务
JTA可以解决跨多个数据源的事务问题,但是性能较差,使用的话要慎重,可以考虑采用补偿机制等来解决,例如先执行a(), 接着执行b() ,如果a()执行成功,b()执行失败,那么再执行一下c(),c()是a()的反操作。
代码示例:
public class JTATransactionMain {
    public static void main(String[] args) throws Exception{
        UserTransaction tx = null;
        try{
            Properties props = new Properties();
            props.put(Context.INITIAL_CONTEXT_FACTORY, jndi_factory);// weblogic.jndi.WLInitialContextFactory
            props.put(Context.PROVIDER_URL, jndi_url);// t3://localhost:7001
            Context ctx = new InitialContext(props);
            tx=  (UserTransaction)ctx.lookup("transaction_url");
            //事务开始
            tx.begin();
            //执行。。。
           
            //事务提交
            tx.commit();
        }catch (Exception e){
            e.printStackTrace();
            tx.rollback();
        }
    }
}

5.iBatis事务

SqlMapClient client = null;
try{
//开始事务
    client.startTransaction();
    client.insert("savePerson",person1);
    client.insert("savePerson",person2);
//提交事务
    client.commitTransaction();
}catch (Exception e){
    e.printStackTrace();
}finally {
//回滚事务
    client.endTransaction();
}
同其他的事务代码不太一样的是,他没有rollback,iBatis是在endTransaction中rollback的。





猜你喜欢

转载自frank1234.iteye.com/blog/2170793
今日推荐