1. 程式人生 > >JAVA程式設計118——事務控制/動態代理

JAVA程式設計118——事務控制/動態代理

一、目錄結構

在這裡插入圖片描述

二、資料庫結構及測試資料

在這裡插入圖片描述

三、程式碼詳解

1、xml配置檔案:pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<modelVersion>4.0.0</modelVersion> <groupId>com.mollen</groupId> <artifactId>exam</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>junit</groupId> <
artifactId
>
junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency
>
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <dependency> <groupId>commons-dbutils</groupId> <artifactId>commons-dbutils</artifactId> <version>1.6</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <target>1.7</target> <source>1.7</source> </configuration> </plugin> </plugins> </build> </project>
2、資料來源配置檔案:db.properties
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/my_db2
jdbc.user=root
jdbc.password=root
3、實體類:Account.java
package com.mollen.bean;

/**
 * @ClassName: Account
 * @Auther: Mollen
 * @CreateTime: 2018-11-06  11:53:29
 * @Description:
 */
public class Account {
    private int id;
    private String name;
    private double money;

    public Account() {
    }

    public Account(int id, String name, double money) {
        this.id = id;
        this.name = name;
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
    
    //...getter/setter
}
4、dao層:

1、Dao介面:AccountDao.java

package com.mollen.dao;

import com.mollen.bean.Account;

/**
 * @ClassName: AccountDao
 * @Auther: Mollen
 * @CreateTime: 2018-11-06  11:55:11
 * @Description:
 */
public interface AccountDao {

    /**
     * 1.根據使用者名稱查詢賬戶資訊
     * @return
     */
    public Account findByName(String name) throws Exception;

    /**
     * 2.更新賬戶資訊
     */
    public void upDate(String name,double money) throws Exception;

}

2、Dao實現類:AccountDaoImpl.java

package com.mollen.dao.impl;

import com.mollen.bean.Account;
import com.mollen.dao.AccountDao;
import com.mollen.utils.JdbcUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;

import java.sql.SQLException;

/**
 * @ClassName:  AccountDaoImpl
 * @Auther:     Mollen
 * @CreateTime: 2018-11-06  11:58:35
 * @Description:
 */
public class AccountDaoImpl implements AccountDao {

    QueryRunner queryRunner = new QueryRunner();

    public void setQueryRunner(QueryRunner queryRunner) {
        this.queryRunner = queryRunner;
    }

    /**
     * 1.根據使用者名稱查詢賬戶資訊
     * @return
     */
    public Account findByName(String name) throws SQLException{
            return   queryRunner.query(JdbcUtils.getConnection(),"SELECT * FROM account WHERE name = ?",new BeanHandler<Account>(Account.class),name);
    }

    /**
     * 2.更新賬戶資訊
     */
    public void upDate(String name,double money) throws SQLException{
            queryRunner.update(JdbcUtils.getConnection(),"UPDATE account SET money = ? WHERE name = ?",money,name);
    }

}

5、Service層:

1、Service層介面:AccountService.java

package com.mollen.service;

/**
 * @ClassName: AccountService
 * @Auther: Mollen
 * @CreateTime: 2018-11-06  14:13:50
 * @Description:
 */
public interface AccountService {

    /**
     * 轉賬業務
     * @param source
     * @param target
     * @param money
     * @throws Exception
     */
    public void transfer(String source,String target,double money) throws Exception;

}

2、Service介面實現類:AccountServiceImpl.java

package com.mollen.service.impl;

import com.mollen.bean.Account;
import com.mollen.dao.AccountDao;
import com.mollen.dao.impl.AccountDaoImpl;
import com.mollen.service.AccountService;

/**
 * @ClassName: AccountServiceImpl
 * @Auther: Mollen
 * @CreateTime: 2018-11-06  14:17:16
 * @Description:
 */
public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao = new AccountDaoImpl();

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public void transfer(String source, String target, double money) throws Exception {
        //1.查詢轉出賬戶的賬戶餘額
        Account source_account = accountDao.findByName(source);
        //2.轉出賬戶的餘額減少
        source_account.setMoney(source_account.getMoney()-money);
        //3.修改轉出賬戶餘額
        accountDao.upDate(source,source_account.getMoney());

        //手動丟擲異常
        //int i = 10 /0 ;

        //1.查詢轉入賬戶的餘額
        Account target_account = accountDao.findByName(target);
        //2.轉入賬戶餘額增加
        target_account.setMoney(target_account.getMoney()+money);
        //3.修改轉入賬戶的餘額
        accountDao.upDate(target,target_account.getMoney());

    }
}

6、建立jdbc工具類:JdbcUtils.java

package com.mollen.utils;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;

/**
 * @ClassName:  JdbcUtils
 * @Auther:     Mollen
 * @CreateTime: 2018-11-06  14:49:43
 * @Description:
 *
 */
public class JdbcUtils {

    //1.建立執行緒標誌物件儲存物件(保證事務過程中用的是同一個連線)
    private static ThreadLocal<Connection> threadLocal = new InheritableThreadLocal<>();

    //3.獲取執行緒池連線物件
    public static Connection getConnection(){
        //獲取標誌
        Connection connection = threadLocal.get();
        try {
            if (connection == null) {
                connection  = JdbcUtils.getDataSource().getConnection();
                //存入標誌
                threadLocal.set(connection);
            }
            return connection;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //4.獲取資料來源
    public static DataSource getDataSource() throws IOException, PropertyVetoException {

        ComboPooledDataSource dataSource = new ComboPooledDataSource();

        Properties properties = new Properties();
        InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
        properties.load(is);

        dataSource.setDriverClass(properties.getProperty("jdbc.driverClass"));
        dataSource.setJdbcUrl(properties.getProperty("jdbc.jdbcUrl"));
        dataSource.setUser(properties.getProperty("jdbc.user"));
        dataSource.setPassword(properties.getProperty("jdbc.password"));

        return dataSource;
    }

    //5.解除執行緒與連線繫結
    public static void remove(){
        threadLocal.remove();
    }
}

7、建立事務類:TransactionManager.java

package com.mollen.utils;

import java.sql.SQLException;

/**
 * @ClassName: TransactionManager
 * @Auther: Mollen
 * @CreateTime: 2018-11-06  14:49:58
 * @Description:
 */
public class TransactionManager {

    /**
     * 1.開啟事務
     */
    public static void startTransaction(){
        try {
            JdbcUtils.getConnection().setAutoCommit(false);
            System.out.println("事務開啟!");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 2.提交事務
     */
    public static void commitTransaction(){
        try {
            JdbcUtils.getConnection().commit();
            System.out.println("事務提交!");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    /**
     * 3.回滾事務
     */
    public static void rollbackTransaction(){
        try {
            JdbcUtils.getConnection().rollback();
            System.out.println("事務回滾!");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 4.關閉連線
     */
    public static void close(){
        try {
            JdbcUtils.getConnection().close();
            System.out.println("連線關閉!");
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }
}

8、建立動態代理測試類

package com.mollen.test;

import com.mollen.service.AccountService;
import com.mollen.service.impl.AccountServiceImpl;
import com.mollen.utils.TransactionManager;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.junit.Test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


/**
 * @ClassName: MyTest
 * @Auther: Mollen
 * @CreateTime: 2018-11-06  18:41:31
 * @Description:
 */

public class MyTest {
    AccountService accountService = new AccountServiceImpl();


    /**
     * 1、第一種方案:Jdk動態代理方式進行事務控制 --> 真實物件必須實現介面
     */
    @Test
    public void transfer1() {
        /**
         *  ClassLoader loader, 真實物件的類載入器
         *  Class<?>[] interfaces, 真實物件實現的所有介面
         *  InvocationHandler h  代理物件的處理類
         */
        AccountService accountService_proxy = (AccountService) Proxy.newProxyInstance(
                accountService.getClass().getClassLoader(),
                accountService.getClass().getInterfaces(),
                new InvocationHandler() {
                    /**
                     * 呼叫代理物件任意方法,InvocationHandler中的invoke()都會執行
                     * @param proxy  代理物件
                     * @param method 代理物件呼叫的方法
                     * @param args  代理物件呼叫方法時摻入的引數
                     * @return
                     * @throws Throwable
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //宣告一個事務執行結果
                        Object obj = null;
                        try {
                            //1.開啟事務--業務執行之前
                            TransactionManager.startTransaction();
                            //2.執行業務--執行業務操作
                            obj = method.invoke(accountService, args);
                            //3.提交事務--業務正常執行
                            TransactionManager.commitTransaction();
                        } catch (Exception e) {
                            e.printStackTrace();
                            //4.回滾事務--業務執行異常
                            TransactionManager.rollbackTransaction();
                        } finally {
                            //5.關閉連線
                            TransactionManager.close();
                        }
                        return obj;
                    }
                });
        try {
            accountService_proxy.transfer("aaa", "bbb", 100);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 2、第二種方案:使用cglib動態代理技術
     */
    @Test
    public void transfer2() {
        //1. 建立cglib的核心物件
        Enhancer enhancer = new Enhancer();
        //2. 設定產生的代理物件的父類
        enhancer.setSuperclass(accountService.getClass());
        //3. 設定呼叫代理物件的回撥函式
        enhancer.setCallback(new MethodInterceptor() {
            /**
             *
             * @param proxy  代理物件
             * @param method 代理物件執行的方法
             * @param args   代理物件呼叫方法時傳入的引數
             * @param methodProxy  呼叫方法的代理物件  一般沒什麼用
             * @return
             * @throws Throwable
             */
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                Object obj = null;
                try {
                    //1. 在轉賬業務執行之前  開啟事物
                    TransactionManager.startTransaction();
                    //2. 執行原有的轉賬業務
                    obj = method.invoke(accountService, args);
                    //3. 轉賬業務執行成功-- 提交事物
                    TransactionManager.commitTransaction();
                } catch (Exception e) {
                    e.printStackTrace();
                    //4. 轉賬業務執行失敗---回滾事物
                    TransactionManager.rollbackTransaction();
                } finally 
            
           

相關推薦

JAVA程式設計118——事務控制/動態代理

一、目錄結構 二、資料庫結構及測試資料 三、程式碼詳解 1、xml配置檔案:pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.or

JAVA程式設計119——事務控制/動態代理/程式碼優化

一、優化方案:將代理類單獨抽取出來封裝成為一個代理工廠 package com.mollen.config; import com.mollen.utils.TransactionManager; import net.sf.cglib.proxy.Enhancer; import n

Java框架之Spring02-AOP-動態代理-AspectJ-JdbcTemplate-事務

AOP 動態代理   代理設計模式的原理:使用一個代理將原本物件包裝起來,然後用該代理物件”取代”原始物件。任何對原始物件的呼叫都要通過代理。代理物件決定是否以及何時將方法呼叫轉到原始物件上。 代理模式的三要素: 代理主題介面 代理者 被代理者 代理模式的主要優點 代理模式在客戶端與目標物

Java實現AOP切面(動態代理

定義 row ack tcl getc java的反射機制 div implement reat Java.lang.reflect包下,提供了實現代理機制的接口和類: public interface InvocationHandler InvocationHandl

java反射機制應用之動態代理

代理類 過多 size bject interface 並且 編譯期 代理 抽象 1.靜態代理類和動態代理類區別 靜態代理:要求被代理類和代理類同時實現相應的一套接口;通過代理類的對象調用重寫接口的方法時,實際上執行的是被代理類的同樣的 方法的調用。 動態代理:在程序運

Java高階特性—反射和動態代理

1).反射   通過反射的方式可以獲取class物件中的屬性、方法、建構函式等,一下是例項: 2).動態代理   使用場景:       在之前的程式碼呼叫階段,我們用action呼叫service的方法實現業務即可。     由於之前在service中實現的業務可能不能夠滿足當先客戶的要求,需要我們重

25(java中的反射和動態代理

1 概述 反射獲取的都是class物件,以下是在不同的階段獲取物件的方式。 2 原始檔階段class物件的作用 可以利用全類名創造物件,具體程式碼為: 3 class物件獲取類中的欄位(即成員變數) 註釋:通過Class.forName()獲取到了Pe

JAVA中的JDK的動態代理

在java的動態代理機制中,有兩個重要的類或介面,一個是 InvocationHandler(Interface)、另一個則是 Proxy(Class) 當我們通過代理物件呼叫一個方法的時候,這個方法的呼叫就會被轉發為由InvocationHandler這個介面的 invoke 方法來進行呼叫。

Java基礎加強總結之動態代理(Proxy)

一、代理的概念 動態代理技術是整個java技術中最重要的一個技術,它是學習java框架的基礎,不會動態代理技術,那麼在學習Spring這些框架時是學不明白的。   動態代理技術就是用來產生一個物件的代理物件的。在開發中為什麼需要為一個物件產生代理物件呢?   舉一個現實生活中

java,簡單實現cglib動態代理

Cglib是動態代理的一種實現方式,用來代理普通的javaBean, /** * 實現MethodInterceptor * @author MyComputer * */ public class CGLibProxy implements MethodInt

java程式設計思想之控制執行流程

java 使用了c的所有流程控制語句,涉及的關鍵字包括 if-else、while、do - while 、for 、 return 、break以及選擇語句switch。 1、true和false 所有條件語句都利用條件表示式的真或假來決定執行路徑 2、 if - elseif -

Java 理論與實踐: 用動態代理進行修飾

動態代理為實現許多常見設計模式(包括 Facade、Bridge、Interceptor、Decorator、Proxy(包括遠端和虛擬代理)和 Adapter 模式)提供了替代的動態機制。雖然這些模式不使用動態代理,只用普通的類就能夠實現,但是在許多情況下,動態代理方式更方便、更緊湊,可以清除許多手寫或

【八】Java設計模式GOF23之動態代理(原生JDK和CGLIB)

一、使用JDK原生動態代理 基於Java反射機制。 Java動態代理是基於介面的,如果物件沒有實現介面則選擇用CGLIB方式實現動態代理。 實現步驟: 1.首先實現一個InvocationHandler,方法呼叫會被轉發到該類的invoke()方法。 2.然後在需要

Java程式設計拾遺『控制流程』

與任何程式設計語言一樣,Java使用條件語句和迴圈結構確定控制流流程。 1. 條件語句 條件語句就是使用if進行條件判斷,及邏輯處理,主要包含以下幾種形式。 1.1 if 單if條件語句格式如下: if (condition) { statement; } 如果

java 系列(一) 動態代理(下)

前兩章想必大家都知道動態代理是怎麼回事,本小節的內容是動態代理的實踐操作了。在Android專案中如何實現按鈕的防雙擊(防抖動)。 這個在Android上又叫Hook技術 1.前言 對於一些特定需求使用也是非常無可奈何的,比如And

Java設計模式Proxy之動態代理

Java動態代理主要涉及到兩個類: InvocationHandler:該介面中僅定義了一個Object : invoke(Object proxy, Method method, Object[] args);引數proxy指代理類,method表示被代理的方法,args

Java程式設計思想_控制執行流程

    return:指定一個方法返回什麼值(假設它沒void返回值);導致當前方法退出,並返回那個值。    break和continue:break用於強行退出迴圈,不執行迴圈中剩餘的語句;                                   contin

java類載入器和動態代理

import java.lang.reflect.*; import java.util.ArrayList; import java.util.Collection; public class ProxyTest { public static void main(String[] args) throw

java如何檢視jvm中動態代理class類內容

在看dubbo原始碼時,發現dubbo呼叫過程設計到了很多動態代理類技術,但是這些動態代理類都是執行在記憶體中的,沒有生成clas

java開發必學知識:動態代理

目錄 1. 引言 2. 代理模式及靜態代理 2.1 代理模式說明 2.2 靜態代理 2.3 靜態代理侷限性 3. 動態代理 3.1 JAVA反