JAVA-transaction, transaction interview questions, mysql transaction, jdbc transaction, DButils transaction, use transaction to complete the transfer function.

1. The characteristics and isolation level of the transaction-(interview questions)

  1. Transaction characteristics ACID
  • Atomicity: refers to the transaction is an indivisible unit of work, operations in the transaction. Either it all happens, or it doesn't happen.
  • Consistency: In a transaction, the integrity of the data before and after the transaction must be consistent.
  • Isolation: When multiple users access the database concurrently, the transaction of one user cannot be interfered by the transactions of other users, and the data between multiple concurrent transactions must be isolated from each other.
  • Durability: Once a transaction is committed, its changes to the data in the database are permanent, and there should be no impact on it even if the database fails.
  1. Concurrent access problems-caused by isolation
    If isolation is not considered, there are three concurrent access problems in transactions.
  • Dirty read: Transaction B has read data that has not yet been committed by Transaction A ------ Transaction B is required to read the data submitted by Transaction A
  • Non-repeatable read: The content of the data read twice in a transaction is inconsistent-the requirement is that the data is consistent when read multiple times in a transaction-unpdate
  • Phantom read/virtual read: The amount of data read twice in a transaction is inconsistent ----- The amount of data read multiple times in a transaction is required to be the same-insert delete

3. The isolation level of the transaction

  • read uncommitted : Read data that has not been submitted: No problem can be solved
  • read committed: Read the submitted data: Dirty reads can be solved ---- oracle default
  • repeatable read: Reread read: Dirty reads and non-repeatable reads can be solved—mysql default
  • serializable: Serialization: can solve dirty reads, non-repeatable reads and virtual reads—equivalent to lock tables

Isolation levels of performance :
read uncommitted> read committed> repeatable read> serialazable
Security:
read uncommitted < read committed< repeatable read<serialazable

Two, MySQL transaction

1. What is a transaction

A thing has n constituent units or these n constituent units succeed at the same time or n units fail at the same time. Is to put n components into one transaction

2. The
default transaction of mysql transaction :

A SQL statement is a transaction by default to open the transaction and commit the transaction

Manual transaction :

  • Open a transaction displayed: start transaction
  • Transaction submission: Commit represents that all sql from the start of the transaction to the transaction submission is considered to be effective and truly update the database. If you forget to write commit, the transaction will be rolled back by default
  • Transaction rollback: rollback represents the rollback of the transaction. All SQL operations from the opening of the transaction to the transaction rollback are considered invalid and the database has not been updated

Case:
1. We first create a database, the table is named account

START TRANSACTION;
INSERT INTO account VALUES(NULL,'jack',5000);
COMMIT;

The above sql statement is executed, and the transaction is executed successfully.

2. If we did not write a commit

START TRANSACTION;
INSERT INTO account VALUES(NULL,'lucy',5000);

Then you can query the data in the cmd window, but the data does not exist in the disk but is printed in the log file.

3. The rollback of the transaction

START TRANSACTION;
INSERT INTO account VALUES(NULL,'amy',5000);
ROLLBACK;

The sql statement cannot be inserted because the transaction is rolled back

Three, JDBC transaction operation

The default is automatic transaction :

Execute the sql statement: executeUpdate() ---- Each time the executeUpdate method is executed, the transaction is automatically submitted.

Manual transaction via jdbc API :

Open the transaction: conn.setAutoComnmit(false);
Commit the transaction: conn.commit();
Roll back the transaction: conn.rollback();
Note: The connnection of the control transaction must be the same
The connection that executes sql and the connnection that starts the transaction must be the same to control the transaction

//通过jdbc去控制事务
		Connection connection=null;
		//1.注册驱动
		try {
    
    Class.forName("com.mysql.jdbc.Driver");
		//2.获取连接
		connection= DriverManager.getConnection("jdbc:mysql:///web19","root","123");
		//手动开启事务
		connection.setAutoCommit(false);
		//3.获取执行平台
		Statement statement =connection.createStatement();
		//4.操作sql
		statement.executeUpdate("insert into account values(null,'zhangsan',6000)");
		
		//statement.executeUpdate("insert into account values(null,'lisi',7000)");
		
		//提交事务
		connection.commit();
		//关闭
		statement.close();
		connection.close();
		}catch (Exception e) {
    
    
			// TODO: handle exception
			try {
    
    
				connection.rollback();
			} catch (SQLException e1) {
    
    
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			e.printStackTrace();
		}

Four, DBUtils transaction operation

QueryRunner
Parametric structure: QueryRunner runner = new QueryRunner(DataSource dataSource);
a parameterized structure passes the data source (connection pool) as a parameter to QueryRunner, QueryRunner will obtain a database connection resource from the connection pool to operate the database, so directly use the update method without Connection parameter You can operate the database

No parameter structure: QueryRunner runner = new QueryRunner();
The parameterless construction does not pass the data source (connection pool) as a parameter to QueryRunner, then we must use the method with Connection parameter when using the QueryRunner object to operate the database

To put it simply, when our sql needs transaction control, it uses a parameterless structure, and does not require transaction control to use a parameterized structure.

QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
		Connection conn=null;
		try {
    
    
			//获得一个Connection
			conn =DataSourceUtils.getConnection();
			//开启事务
			conn.setAutoCommit(false);
			//runner.update("update account set money=1000 where name='tom");
			runner.update(conn, "update account set money=1000 where name='tom");
			//提交或回滚事务
			conn.commit();
		} catch (SQLException e) {
    
    
			try {
    
    
				conn.rollback();
			} catch (SQLException e1) {
    
    
				
				e1.printStackTrace();
			}
			e.printStackTrace();
		}
	}

Five, complete a transfer function case

First analyze the web transfer function in MVC mode
Insert picture description here

The first step: write a jsp first

<form action="${pageContext.request.contextPath}/transfer" method="post">
			转出账户:<input type="text" name="out"><br/>
			转入账户:<input type="text" name="in" ><br/>
			转账金额:<input type="text" name="money"><br/>
			<input type="submit" value="确认转账"><br/>
</form>

Step 2: Write the web layer, responsible for obtaining the data of the page, call the data of the service layer, the
web layer is a servlet, you need to build a servlet by yourself

@WebServlet("/transfer")
public class TransferServlet extends HttpServlet {
    
    
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
		//接受转账的参数
		String out = request.getParameter("out");
		String in =request.getParameter("in");
		String moneyStr =request.getParameter("money");
		double money =Double.parseDouble(moneyStr);
		//调用业务层的转账方法
		TransferService service =new TransferService();
		boolean isTransferSuccess= service.tranfer(out,in,money);
		response.setContentType("text/html;charset=UTF-8");
		if (isTransferSuccess) {
    
    
			response.getWriter().write("转账成功!!!");
		}else {
    
    
			response.getWriter().write("转账失败!!");
		}
	}

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

}

Step 3:
Write the dao layer, process the data in the database, and feed it back to the service layer

public void out(Connection conn,String out, double money) throws SQLException {
    
    
		QueryRunner queryRunner =new QueryRunner();
		//Connection conn =DataSourceUtils.getConnection();
		String sql ="update account set money =money-? where name=?";
		queryRunner.update(conn,sql,money,out);
		
	}

	public void in(Connection conn,String in, double money) throws SQLException {
    
    
		QueryRunner queryRunner =new QueryRunner();
		//Connection conn =DataSourceUtils.getConnection();
		String sql ="update account set money =money+? where name=?";
		queryRunner.update(conn,sql,money,in);
		
	}

Step 4:
Write the service layer

public boolean tranfer(String out, String in, double money) {
    
    
		//创建dao对象
		TransferDao dao =new TransferDao();
		
		boolean isTranferSuccess =true;
		Connection conn=null;
		try {
    
    
			conn =DataSourceUtils.getConnection();
			conn.setAutoCommit(false);
			
			//转出方法
			dao.out(conn,out,money);
			//转入方法
			dao.in(conn,in,money);
		} catch (Exception e) {
    
    		
			isTranferSuccess =false;	
			//回滚事务
			try {
    
    
				conn.rollback();
			} catch (SQLException e1) {
    
    
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			e.printStackTrace();
		}finally {
    
    
			try {
    
    
				conn.commit();
			} catch (SQLException e) {
    
    
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}	
		return isTranferSuccess;
	}

Sixth, upgraded version: use ThreadLocal to bind connection resources

Because we want to use transactions, it does not conform to the MVC model. In our code above, Connection is used in the Service layer. But Connection, appears in the database. Should be used in the dao layer. So we should recommend the ThreadLocal method.
The ThreadLocal method uses the knowledge of threads. We will transfer this line and complete it on a thread.

Step 1:
Writing tools

public class MyDataSourceUtils {
    
    
	//获取Connection------从连接池中获取
	private static ComboPooledDataSource dataSource =new ComboPooledDataSource();	
	//创建ThreadLocal-------相当于一个map集合
	private static ThreadLocal<Connection> tl =new ThreadLocal<Connection>();
	
	//开启事务
	public static void startTransaction() throws SQLException {
    
    
		Connection connection= getCurrentConnection();
		connection.setAutoCommit(false);
	}
	
	//获得当前线程上绑定的conn
	public static Connection getCurrentConnection() throws SQLException {
    
    
		//从ThreadLocal寻找当前线程是否有对应Connection
		Connection conn =tl.get();
		if (conn ==null) {
    
    
			//获得新的connection
			conn=getConnection();
			//将conn资源绑定到ThreadLocal(map)上
			tl.set(conn);
		}
		return conn;
	}
	
	public static Connection getConnection() throws SQLException {
    
    
		return dataSource.getConnection();
	}
	
	//事务回滚
	public static void rollback() throws SQLException {
    
    
		getCurrentConnection().rollback();
	}
	//事务提交
	public static void commit() throws SQLException {
    
    
		getCurrentConnection().commit();
		//将Connection从ThreadLocal中移除
		tl.remove();
		getCurrentConnection().close();
	}
}

Step 2:
Modify the service layer

public class TransferService {
    
    

	public boolean tranfer(String out, String in, double money) {
    
    
		//创建dao对象
		TransferDao dao =new TransferDao();
		
		boolean isTranferSuccess =true;
		Connection conn=null;
		try {
    
    
			//开启事务
			//conn =DataSourceUtils.getConnection();
			//conn.setAutoCommit(false);
			//使用ThreadLocal存储Connection
			MyDataSourceUtils.startTransaction();
			
			//转出方法
			dao.out(out,money);
			//转入方法
			//int i=1/0;
			dao.in(in,money);
		} catch (Exception e) {
    
    
			
			isTranferSuccess =false;	
			//回滚事务
			try {
    
    
				MyDataSourceUtils.rollback();
			} catch (SQLException e1) {
    
    
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			e.printStackTrace();
		}finally {
    
    
			try {
    
    
				MyDataSourceUtils.commit();
			} catch (SQLException e) {
    
    
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}	
		return isTranferSuccess;
	}

}

Step 3:
Modify the dao layer

public class TransferDao {
    
    

	public void out(String out, double money) throws SQLException {
    
    
		QueryRunner queryRunner =new QueryRunner();
		Connection conn =MyDataSourceUtils.getCurrentConnection();
		String sql ="update account set money =money-? where name=?";
		queryRunner.update(conn,sql,money,out);
		
	}

	public void in(String in, double money) throws SQLException {
    
    
		QueryRunner queryRunner =new QueryRunner();
		Connection conn =MyDataSourceUtils.getCurrentConnection();
		String sql ="update account set money =money+? where name=?";
		queryRunner.update(conn,sql,money,in);
		
	}

}

Note that ThreadLocal is a map collection. Its key is mainly the thread name, and the value only needs to be placed in our connection.

Guess you like

Origin blog.csdn.net/Mr_GYF/article/details/109125561