[Local things] Summary, native sample applications

Four characteristics of database things

This article describes the characteristics of things (ACID), and writes local things tool classes based on QueryRunner.

1. Atomicity (A)

The so-called atomicity means that during the operation of the entire transaction, either all succeed or all fail, and it will not be in an intermediate state. In the process of opening a transaction, data operations are performed on the database. If an error occurs in the process, all operations will be rolled back without any impact on the database.

2. Consistency (C)

Consistency means that the transaction must always maintain consistency when the database changes from one state to another. As an example of redirection, suppose user A has 100 yuan and user B has 200 yuan. If user A transfers 50 yuan to user B in a transaction, then no matter what happens, more or less concurrency, as long as the data If it is applied to the database (that is, the transaction is executed successfully), then the A user account has 50 yuan left, and the B account has 250 yuan left. This is the consistency of the transaction.

3. Isolation (I)

Isolation means that when multiple users operate the database concurrently, such as operating a table at the same time, the database opens a transaction for each user, and the transaction will not affect each other, and other transactions will not be perceived during the operation. .

4. Durability (D)

Persistence means that after the transaction is committed, all data processes operating within the transaction will be applied to the database, even if a failure occurs, there will be no impact.

Local things tools

Use QueryRunner to encapsulate database connection information. Use annotations to identify transactions and use ThreadLocal to save variables. Called thread local variables, also called thread local storage, the method is different, in fact, the meaning is similar. The variable can be taken out for operation at any time in a thread. Proxy the service, open the transaction before the business is executed, close the transaction after the execution, and execute the error rollback transaction. Look at the code.

- Creating notes

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/** 
 * 对事物进行管理 注解
 * @author zfl
 *
 */
@Retention(RetentionPolicy.RUNTIME) //将注解保存在运行期间
@Target(value=ElementType.METHOD)  //运用到方法上面
public @interface Tran {
    
    
}

- Creating things Manager

Responsible for opening transactions, committing transactions, opening transactions, obtaining data sources, etc.

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

/**
 * 对事物进行管理
 * @author zfl
 *
 */
public class TransactionManager {
    
    

	private static DataSource dataSource = new ComboPooledDataSource();
	
	private static ThreadLocal<Connection> conn_local = new ThreadLocal<Connection>();

	private static ThreadLocal<Boolean> flag_local = new ThreadLocal<Boolean>(){
    
      //标志是否开启过事务,默认为false
		protected Boolean initialValue() {
    
    return false;};
	};

	private static ThreadLocal<Connection> realConn_local = new ThreadLocal<Connection>(); //存放真正的链接,用于关闭真正的链接
	public static void start() throws SQLException{
    
    
		flag_local.set(true);
		final Connection connection = dataSource.getConnection();
		connection.setAutoCommit(false);  //开启事务  //设置自动提交为false
		realConn_local.set(connection);   //存放真正的链接
		Connection proxyConnection = (Connection) Proxy.newProxyInstance(connection.getClass().getClassLoader(), connection.getClass().getInterfaces(), 
					new InvocationHandler() {
    
    
						public Object invoke(Object proxy, Method method, Object[] args)
								throws Throwable {
    
    
							if("close".equals(method.getName())){
    
      //针对close方法进行处理
								return null;  //不关闭链接
							} else{
    
    
								return method.invoke(connection, args);
							}
						}
					});    //代理连接的close方法做了修改,不真正的关闭
		//保存代理链接,不管理close方法,但是最后链接还是要关闭的,要不然太浪费资源
		conn_local.set(proxyConnection);
	}

	
	public static void commit() throws SQLException{
    
      //提交
		conn_local.get().commit(); 
	}
	
	public static void rollback() throws SQLException{
    
      //回滚
		conn_local.get().rollback();
	}


	/*
	 * 为了解决在事务中获取链接或者在普通获取链接中的通用性考虑时,使用以下方法解决。
	 * 解决DataSource中的getConnection方法。判断当前是否开启了事务。
	 * 本没有问题,但是由于QueryRunner中的链接是在执行过后会自动关闭,所以又要对Connection中的close方法进行处理
	 */
	public static DataSource getDataSource(){
    
    
		
		if(flag_local.get()){
    
      //如果为true代表开启过事务,返回能返回相同链接的数据源
			return (DataSource) Proxy.newProxyInstance(dataSource.getClass().getClassLoader(), dataSource.getClass().getInterfaces(), 
					 new InvocationHandler() {
    
    
						public Object invoke(Object proxy, Method method, Object[] args)
								throws Throwable {
    
    
							if("getConnection".equals(method.getName())){
    
    
								return conn_local.get();
							} else{
    
    
								return method.invoke(dataSource, args); //对不是getConnection的方法,不进行处理
							}
						}
					});
		} else{
    
    
			return dataSource;
		}
	}
	
	/**
		释放连接
	*/
	public static void release(){
    
    
		try {
    
    
			realConn_local.get().close(); //关闭链接
		} catch (SQLException e) {
    
    
			e.printStackTrace();
			throw new RuntimeException(e);
		}
		realConn_local.remove();
		conn_local.remove();
		flag_local.remove();
	}
}

- Business Layer

Use the creation of the factory management object to determine whether the transaction annotation is added to the method when the service object is generated. Add a transaction if it is added, otherwise do not add a transaction.

Load object property configuration file

private static Properties pro = new Properties();
	static{
    
    
		InputStream inStream=null;
		try {
    
    
			inStream = BeanFactory.class.getClassLoader().getResourceAsStream("instance.properties");
			pro.load(inStream);
		} catch (Exception e) {
    
    
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

Create service proxy object

//获取service
	public static <T extends Service> T getService(Class<T> clazz){
    
    
		String simpleName = clazz.getSimpleName();
		String className = pro.getProperty(simpleName);
		final T service;
		try {
    
    
			service = (T) Class.forName(className).newInstance();
		} catch (Exception e) {
    
    
			e.printStackTrace();
			throw new RuntimeException(e);
		}
		//添加事务  生成service代理
		@SuppressWarnings("all")
		T proxyService = (T) Proxy.newProxyInstance(service.getClass().getClassLoader(), service.getClass().getInterfaces(), 
				new InvocationHandler() {
    
    
					public Object invoke(Object proxy, Method method, Object[] args)
							throws Throwable {
    
    
						if(method.isAnnotationPresent(Tran.class)){
    
     //如果有注解,添加事务
							Object obj = null;
							try {
    
    
								TransactionManager.start();
								obj = method.invoke(service, args);
								TransactionManager.commit();
							} catch(InvocationTargetException e){
    
      //底层代码抛出的异常
								TransactionManager.rollback();
								throw new RuntimeException(e.getTargetException());  //转换成底层异常抛出
							} catch (Exception e) {
    
    
								TransactionManager.rollback();
								throw new RuntimeException(e);
							} finally{
    
    
								TransactionManager.release();
							}
							return obj;  //返回数据
						} else{
    
    
							return method.invoke(service, args); //普通方法,则不添加事务
						}
							
					}
				});
		return proxyService;
	}

- practical application

/**
	 * 查询所有的菜品
	 * @throws SQLException 
	 */
public void add(Food food) throws SQLException {
    
    
		QueryRunner qr = new QueryRunner(TransactionManager.getDataSource()); //获取datasouce数据源
		String sql = "insert into food(foodName,foodType_id,price,mprice,description,img)" +
				" values(?,?,?,?,?,?)";
		Object[]params ={
    
    food.getFoodName(),food.getFoodType().getId(),food.getPrice(),food.getMprice(),food.getDescription(),food.getImg()};
		qr.update(sql, params);
	}

Guess you like

Origin blog.csdn.net/qq_37640410/article/details/108465362