JavaWeb:业务层两种事务管理方式

业务层事务管理

  • 事务管理
    • DAO层事务管理
    • Service层事务管理
    • 事务管理要加在哪里?
  • 例子:转账
    • View、Servlet和Domain代码
      • 事务控制第一种方法:传递Service传递一个Connection给Dao层
      • 事务控制第二种方法:使用ThreadLocal
    • 使用DBUtils的事务控制:传递相同Connection
    • Hibernate事务管理:ThreadLocal

事务管理

DAO层事务管理

dao层一般完成单个数据库操作,使用Connection可以控制单个事务的提交,回滚。

Service层事务管理

service层一般完成一定的业务逻辑,需要使用多个dao的操作组合完成。所以这些操作要么全部完成要么全部不做。也就是一个事务。

事务管理要加在哪里?

答:Service层,控制整个业务逻辑的隔离性。

例子:转账

View、Servlet和Domain代码

View层:

转账页面

付款人:
收款人:
金额:

Domain:


	private Integer id;
	private String name;
	private Double money;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Double getMoney() {
		return money;
	}
	public void setMoney(Double money) {
		this.money = money;
	}

}

Jdbc工具类:

	static ComboPooledDataSource dataSource = null;
	static{
		dataSource=new ComboPooledDataSource();
	}
	
	public static Connection getConnection() throws SQLException{
		return dataSource.getConnection();
	}
	
	public static DataSource getDataSource(){
		return dataSource;
	}
	public static void close(Connection con,PreparedStatement ps,ResultSet rs){
		if(rs!=null){
			try {
				rs.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if(ps!=null){
			try {
				ps.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		if(con!=null){
			try {
				con.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) throws SQLException {
		System.out.println(new JDBCUtils().getConnection());
	}

	public static void startTransaction() {
		startTransaction();
		
	}

Servlet层:调用业务层的服务进行转账

public class AccountServlet extends HttpServlet {
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String from = request.getParameter("from");
		String to = request.getParameter("to");
		request.setCharacterEncoding("utf-8");//post乱码
		Double money = Double.parseDouble(request.getParameter("money"));
		
		//处理数据
		AccountService service = new AccountService();
		try {
			service.transfer(from ,to ,money);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

事务控制第一种方法:传递Service传递一个Connection给Dao层

Service层分析:分别调用Dao层的两个方法,完成一个事务,一个事务必须使用同一个Connection设置自动提交false,在业务层完成事务的提交/回滚。

	 * 事务管理第一种解决办法:向下传递Connection
	 * @param from
	 * @param to
	 * @param money
	 * @throws SQLException
	 */
	public void transfer(String from, String to, Double money) throws SQLException {
		AccountDao accountDao = new AccountDao();
		//方法1:业务层获得Connection 传给dao
		Connection conn = null;
		
		try {
			conn= JDBCUtils.getConnection();
			conn.setAutoCommit(false);
			accountDao.transferOut(from,money,conn);
			int i=1/0;
			accountDao.transferIn(to,money,conn);
		} catch (Exception e) {
			System.out.println("rollback");
			conn.rollback();
			e.printStackTrace();
		}
		conn.commit();
	}

对应Dao层代码:接收Service层的Connection

	 * 第一种:传递Connection
	 * @param from
	 * @param money
	 * @param conn
	 * @throws SQLException
	 *//*
	public void transferOut(String from, Double money, Connection conn) throws SQLException {
		
		//Connection conn = null;
		PreparedStatement ps=null;
		try{
			//conn = JDBCUtils.getConnection();
			String sql = "update account set money = money-? where name =?";
			ps = (PreparedStatement) conn.prepareStatement(sql);
			ps.setDouble(1, money);
			ps.setString(2, from);
			ps.executeUpdate();
		}catch (Exception e) {
			e.printStackTrace();
		}finally {
			ps.close();
			//conn.close();
		}
	}

	public void transferIn(String to, Double money, Connection conn) throws SQLException {
		//Connection conn = null;
		PreparedStatement ps=null;
		try{
			//conn = JDBCUtils.getConnection();
			String sql = "update account set money = money+? where name =?";
			ps = conn.prepareStatement(sql);
			ps.setDouble(1, money);
			ps.setString(2, to);
			ps.executeUpdate();
		}catch (Exception e) {
			e.printStackTrace();
		}finally {
			ps.close();
			//conn.close();
		}
	}

事务控制第二种方法:使用ThreadLocal

ThreadLocal使用Map将一个变量与线程绑定,key是线程,value是与绑定线程的变量。将Connection作为变量与线程绑定,就保证了在执行Service时,每个线程在执行每个Dao操作时,获取同一个Connection。
Service层代码:

	 * 事务管理,使用ThreadLocal
	 * @param from
	 * @param to
	 * @param money
	 * @throws SQLException 
	 */
	public void transfer2(String from, String to, Double money) throws SQLException {
		AccountDao accountDao = new AccountDao();
		Connection conn = null;
		try {
			conn= JDBCUtils2.getConnection();
			JDBCUtils2.startTransaction();
			accountDao.transferOut(from,money);
			//int i=1/0;
			accountDao.transferIn(to,money);
		} catch (Exception e) {
			System.out.println("rollback");
			JDBCUtils2.rollBackTranaction();
			e.printStackTrace();
		}
		JDBCUtils2.commitTransaction();
	}

JDBCUtils2:保证获得的Connection是与当前线程绑定的Conn

	
	static ComboPooledDataSource dataSource = null;
	static final ThreadLocal tl=new ThreadLocal();
	//连接与线程绑定ThreadLocal的Map里放的是
	static{
		dataSource=new ComboPooledDataSource();
	}
	
	public static Connection getConnection() throws SQLException{
		Connection conn = null;
		if(tl.get()==null){
			conn = dataSource.getConnection();
			tl.set(conn); //获取线程时连接放入线程
		}
		return tl.get();//取出线程绑定的连接
		
	}
	
	public static DataSource getDataSource(){
		return dataSource;
	}
	
	public static void close(Connection con,PreparedStatement ps,ResultSet rs){
		if(rs!=null){
			try {
				rs.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if(ps!=null){
			try {
				ps.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		if(con!=null){
			try {
				con.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public static void startTransaction() throws SQLException {
		Connection conn = null;
		conn = tl.get();
		if(conn==null){
			conn=dataSource.getConnection();
			tl.set(conn);
		}
		conn.setAutoCommit(false);//线程绑定的连接设置不自动提交
		
	}
	
	public static void commitTransaction() throws SQLException{
		Connection connection = tl.get();
		connection.commit();   ///线程绑定的连接提交事务
	}
	
	public static  void  rollBackTranaction() throws SQLException{
		Connection connection = tl.get();
		connection.rollback();//线程绑定的连接回滚
	}
}

Dao层代码:获得的链接是与当前线程绑定的Connection

public void transferOut(String from, Double money) throws SQLException {
		Connection conn = null;
		PreparedStatement ps=null;
		try{
			conn = JDBCUtils2.getConnection();
			String sql = "update account set money = money-? where name =?";
			ps = (PreparedStatement) conn.prepareStatement(sql);
			ps.setDouble(1, money);
			ps.setString(2, from);
			ps.executeUpdate();
		}catch (Exception e) {
			e.printStackTrace();
		}finally {
			ps.close();
			//conn.close();
		}
	}
	public void transferIn(String to, Double money) throws SQLException {
		/*//没有事务管理dbutils时这样用
		 * QueryRunner query=new QueryRunner(JDBCUtils.getDataSource());
		String sql = "update account set money = money+? where name =?";
		query.update(sql,money,to);
		*/

		Connection conn = null;
		PreparedStatement ps=null;
		try{
			conn = JDBCUtils2.getConnection();
			String sql = "update account set money = money+? where name =?";
			ps = conn.prepareStatement(sql);
			ps.setDouble(1, money);
			ps.setString(2, to);
			ps.executeUpdate();
		}catch (Exception e) {
			e.printStackTrace();
		}finally {
			ps.close();
			//conn.close();
		}
	}	

使用DBUtils的事务控制:传递相同Connection

Service层:传递普通Connection给dao层

	 * 事务管理,使用Dbutils和第一种类似,都是传递Connection
	 * @param from
	 * @param to
	 * @param money
	 * @throws SQLException 
	 */
	public void transfer(String from, String to, Double money) throws SQLException {
		AccountDao accountDao = new AccountDao();
		Connection conn = null;
		try {
			conn= JDBCUtils.getConnection();
			conn.setAutoCommit(false);
			accountDao.transferOut(from,money,conn);
			int i=1/0;
			accountDao.transferIn(to,money,conn);
		} catch (Exception e) {
			System.out.println("rollback");
			DbUtils.rollbackAndClose(conn);
			e.printStackTrace();
		}
		DbUtils.commitAndCloseQuietly(conn);
	}

dao层使用DBUtils进行数据库操作:

	 * 第一种:DButils
	 * @param from
	 * @param money
	 * @param conn
	 * @throws SQLException
	 */
	public void transferOut(String from, Double money, Connection conn) throws SQLException {
		//有事务管理dbutils时这样用
		QueryRunner query=new QueryRunner();
		String sql = "update account set money = money-? where name =?";
		//传Connection
		query.update(conn,sql,money,from);
		
	}

	public void transferIn(String to, Double money, Connection conn) throws SQLException {
		//有事务管理dbutils时这样用
		QueryRunner query=new QueryRunner();
		String sql = "update account set money = money+? where name =?";
		//传Connection
		query.update(conn,sql,money,to);
	}

Hibernate事务管理:ThreadLocal

Hibernate使用ThreadLocal管理事务,程序员不必编写代码进行控制,只需要在核心配置文件里配置即可设置对应的事务管理级别

thread	

Hibernate工具类里通过SessionFactory的getCurrentSession()获得与线程绑定的Connection,不再配置文件里配置是使用不了这个方法的。

public static  Session getCurrentSeesion(){
		//xml配置以后才可以使用
		return factory.getCurrentSession();
	}

Hibernate使用:

	Session session = HibernateUtils.getCurrentSeesion();
		Transaction transaction = session.beginTransaction();
		Customer c= new  Customer();
		c.setCust_name("王");
		session.save(c);
		transaction.commit();
		//不要关闭session,线程结束会自动关闭

你可能感兴趣的:(数据库,Java,Web)