提交 edb18587 编写于 作者: W wangliang

TransactionLog 事务日志记录

上级 7fd08b82
......@@ -4,9 +4,10 @@ server.port=8090
logging.level.com.codingapi=debug
txlcn.tc.tms=127.0.0.1:8070
txlcn.tc.sql-type=mysql
txlcn.tc.application-name=example-tc
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.password=root
spring.datasource.username=root
\ No newline at end of file
spring.datasource.username=root
......@@ -47,6 +47,12 @@
<artifactId>spring-tx</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
</dependency>
</dependencies>
<build>
......
package com.codingapi.txlcn.tc.aspect;
import com.codingapi.txlcn.p6spy.CompoundJdbcEventListener;
import com.codingapi.txlcn.p6spy.common.ConnectionInformation;
import com.codingapi.txlcn.p6spy.wrapper.ConnectionWrapper;
import com.codingapi.txlcn.tc.info.TransactionInfo;
import com.codingapi.txlcn.tc.jdbc.ProxyConnection;
import lombok.AllArgsConstructor;
......@@ -28,9 +26,7 @@ public class TxDataSourceInterceptor implements MethodInterceptor {
TransactionInfo transactionInfo = TransactionInfo.current();
Connection connection = (Connection) invocation.proceed();
if(transactionInfo!=null&&transactionInfo.hasSqlProxy()) {
return new ProxyConnection(ConnectionWrapper.wrap(connection,
compoundJdbcEventListener,
ConnectionInformation.fromConnection(connection)));
return new ProxyConnection(compoundJdbcEventListener,connection);
}else{
return connection;
}
......
......@@ -20,6 +20,11 @@ import lombok.extern.slf4j.Slf4j;
@Model(flag = "C",value = "TC模块配置信息",color = "#FF88EE")
public class TxConfig {
/**
* 数据库类型
*/
private String sqlType;
/**
* 事务切面
*/
......
......@@ -4,6 +4,7 @@ import com.codingapi.maven.uml.annotation.GraphRelation;
import com.codingapi.maven.uml.annotation.Model;
import com.codingapi.txlcn.tc.event.transaction.TransactionEventContext;
import com.codingapi.txlcn.tc.info.TransactionInfo;
import com.codingapi.txlcn.tc.jdbc.JdbcTransaction;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
......@@ -55,7 +56,7 @@ public class TransactionContext {
transactionStepContext.execute(transactionInfo);
transactionEventContext.onAfterJoinTransaction(transactionInfo);
}
JdbcTransaction.clear();
transactionInfo.clear();
}
......
package com.codingapi.txlcn.tc.jdbc;
import com.codingapi.txlcn.p6spy.CompoundJdbcEventListener;
import org.h2.util.JdbcUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
......@@ -26,4 +27,5 @@ public class JdbcConfiguration {
return new TransactionJdbcEventListener(transactionJdbcEvents);
}
}
package com.codingapi.txlcn.tc.jdbc;
import com.codingapi.txlcn.tc.jdbc.log.TransactionLog;
import lombok.Getter;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
/**
* @author lorne
* @date 2020/7/1
* @description
*/
public class JdbcTransaction {
@Getter
private Connection connection;
private List<TransactionLog> transactionLogs;
public static JdbcTransaction current(){
return JdbcTransactionThreadLocal.current();
}
protected JdbcTransaction(Connection connection){
this.connection = connection;
this.transactionLogs = new ArrayList<>();
JdbcTransactionThreadLocal.push(this);
}
public static void clear() {
JdbcTransactionThreadLocal.push(null);
}
public void add(TransactionLog transactionLog) {
transactionLogs.add(transactionLog);
}
}
package com.codingapi.txlcn.tc.jdbc;
/**
* 事务信息ThreadLocal
* @author lorne 2020-0305
*/
class JdbcTransactionThreadLocal {
final static ThreadLocal<JdbcTransaction> threadLocal = new ThreadLocal<>();
static JdbcTransaction current(){
return threadLocal.get();
}
static void push(JdbcTransaction jdbcTransaction){
threadLocal.set(jdbcTransaction);
}
}
package com.codingapi.txlcn.tc.jdbc;
import com.codingapi.txlcn.p6spy.CompoundJdbcEventListener;
import com.codingapi.txlcn.p6spy.common.ConnectionInformation;
import com.codingapi.txlcn.p6spy.wrapper.ConnectionWrapper;
import java.sql.*;
import java.util.Map;
import java.util.Properties;
......@@ -14,8 +18,11 @@ public class ProxyConnection implements Connection {
private Connection connection;
public ProxyConnection(Connection connection) {
this.connection = connection;
public ProxyConnection(CompoundJdbcEventListener compoundJdbcEventListener, Connection connection) {
new JdbcTransaction(connection);
this.connection = ConnectionWrapper.wrap(connection,
compoundJdbcEventListener,
ConnectionInformation.fromConnection(connection));
}
@Override
......
package com.codingapi.txlcn.tc.jdbc;
import java.sql.Connection;
import java.sql.SQLException;
/**
......@@ -14,5 +13,5 @@ public interface TransactionJdbcEvent {
TransactionJdbcState state();
Object execute(Connection connection, Object param) throws SQLException;
Object execute(Object param) throws SQLException;
}
......@@ -8,7 +8,6 @@ import com.codingapi.txlcn.tc.info.TransactionInfo;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
......@@ -43,42 +42,38 @@ public class TransactionJdbcEventListener extends P6spyJdbcEventListener {
@Override
public String onBeforeAnyExecute(StatementInformation statementInformation) throws SQLException {
Connection connection = statementInformation.getConnectionInformation().getConnection();
String sql = statementInformation.getSqlWithValues();
Optional<TransactionJdbcEvent> optional = getTransactionJdbcEvent(TransactionJdbcState.EXECUTE);
if(!optional.isPresent()){
return sql;
}
return (String)optional.get().execute(connection,sql);
return (String)optional.get().execute(sql);
}
@Override
public void onBeforeCommit(ConnectionInformation connectionInformation, JdbcCallable callable) throws SQLException{
Connection connection = connectionInformation.getConnection();
Optional<TransactionJdbcEvent> optional = getTransactionJdbcEvent(TransactionJdbcState.COMMIT);
if(!optional.isPresent()){
callable.call();
}
optional.get().execute(connection,callable);
optional.get().execute(callable);
}
@Override
public void onBeforeRollback(ConnectionInformation connectionInformation, JdbcCallable callable) throws SQLException {
Connection connection = connectionInformation.getConnection();
Optional<TransactionJdbcEvent> optional = getTransactionJdbcEvent(TransactionJdbcState.ROLLBACK);
if(!optional.isPresent()){
callable.call();
}
optional.get().execute(connection,callable);
optional.get().execute(callable);
}
@SneakyThrows
@Override
public void onAfterAnyExecute(StatementInformation statementInformation, long timeElapsedNanos, SQLException e) {
Connection connection = statementInformation.getConnectionInformation().getConnection();
Optional<TransactionJdbcEvent> optional = getTransactionJdbcEvent(TransactionJdbcState.AFTER);
if(optional.isPresent()){
optional.get().execute(connection,statementInformation);
optional.get().execute(statementInformation);
}
}
}
package com.codingapi.txlcn.tc.jdbc.event;
import com.codingapi.txlcn.tc.jdbc.log.TransactionLogExecutor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
......@@ -17,7 +18,7 @@ public class JdbcEventConfiguration {
}
@Bean
public LcnExecuteTransactionJdbcEvent lcnExecuteTransactionJdbcEvent(){
return new LcnExecuteTransactionJdbcEvent();
public LcnExecuteTransactionJdbcEvent lcnExecuteTransactionJdbcEvent(TransactionLogExecutor transactionLogExecutor){
return new LcnExecuteTransactionJdbcEvent(transactionLogExecutor);
}
}
......@@ -2,8 +2,10 @@ package com.codingapi.txlcn.tc.jdbc.event;
import com.codingapi.txlcn.p6spy.event.JdbcCallable;
import com.codingapi.txlcn.tc.TransactionConstant;
import com.codingapi.txlcn.tc.jdbc.JdbcTransaction;
import com.codingapi.txlcn.tc.jdbc.TransactionJdbcEvent;
import com.codingapi.txlcn.tc.jdbc.TransactionJdbcState;
import lombok.extern.slf4j.Slf4j;
import java.sql.Connection;
import java.sql.SQLException;
......@@ -13,6 +15,7 @@ import java.sql.SQLException;
* @date 2020/7/1
* @description
*/
@Slf4j
public class LcnCommitTransactionJdbcEvent implements TransactionJdbcEvent {
@Override
......@@ -26,7 +29,9 @@ public class LcnCommitTransactionJdbcEvent implements TransactionJdbcEvent {
}
@Override
public Object execute(Connection connection, Object param) throws SQLException {
public Object execute(Object param) throws SQLException {
Connection connection = JdbcTransaction.current().getConnection();
log.info("connection:{}",connection);
JdbcCallable jdbcCallable = (JdbcCallable) param;
jdbcCallable.call();
//不需要返回值,返回固定值1
......
package com.codingapi.txlcn.tc.jdbc.event;
import com.codingapi.txlcn.tc.TransactionConstant;
import com.codingapi.txlcn.tc.jdbc.JdbcTransaction;
import com.codingapi.txlcn.tc.jdbc.TransactionJdbcEvent;
import com.codingapi.txlcn.tc.jdbc.TransactionJdbcState;
import com.codingapi.txlcn.tc.jdbc.log.TransactionLog;
import com.codingapi.txlcn.tc.jdbc.log.TransactionLogExecutor;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.sql.Connection;
......@@ -14,8 +18,11 @@ import java.sql.SQLException;
* @description
*/
@Slf4j
@AllArgsConstructor
public class LcnExecuteTransactionJdbcEvent implements TransactionJdbcEvent {
private TransactionLogExecutor transactionLogExecutor;
@Override
public String type() {
return TransactionConstant.LCN;
......@@ -27,9 +34,15 @@ public class LcnExecuteTransactionJdbcEvent implements TransactionJdbcEvent {
}
@Override
public Object execute(Connection connection, Object param) throws SQLException {
public Object execute(Object param) throws SQLException {
String sql = (String) param;
Connection connection = JdbcTransaction.current().getConnection();
log.info("connection:{}",connection);
log.info("sql=>{}",sql);
TransactionLog transactionLog = new TransactionLog(sql);
transactionLogExecutor.insert(connection,transactionLog);
JdbcTransaction.current().add(transactionLog);
return sql;
}
}
package com.codingapi.txlcn.tc.jdbc.log;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author lorne
* @date 2020/7/1
* @description
*/
@Configuration
public class JdbcLogConfiguration {
@Bean
public TransactionLogExecutor transactionLogExecutor(LogExecutor logExecutor){
return new TransactionLogExecutor(logExecutor);
}
@Bean
@ConditionalOnProperty(name = "txlcn.tc.sql-type",havingValue = "mysql")
public LogExecutor mysqlLogExecutor(){
return new MysqlLogExecutor();
}
}
package com.codingapi.txlcn.tc.jdbc.log;
/**
* @author lorne
* @date 2020/7/1
* @description
*/
public interface LogExecutor {
String insert(TransactionLog transactionLog);
String create();
String delete(long id);
}
package com.codingapi.txlcn.tc.jdbc.log;
/**
* @author lorne
* @date 2020/7/1
* @description
*/
public class MysqlLogExecutor implements LogExecutor {
@Override
public String insert(TransactionLog transactionLog) {
return "insert into `transaction_log`(`id`,`group_id`,`sql`,`time`,`flag`) values(?,?,?,?,?)";
}
@Override
public String create() {
return null;
}
@Override
public String delete(long id) {
return null;
}
}
package com.codingapi.txlcn.tc.jdbc.log;
import com.codingapi.txlcn.tc.info.TransactionInfo;
/**
* @author lorne
* @date 2020/7/1
* @description
*/
public class TransactionLog {
public TransactionLog(String sql) {
//todo ID唯一算法
this.id = System.nanoTime();
this.sql = sql;
this.groupId = TransactionInfo.current().getGroupId();
this.time = System.currentTimeMillis();
this.flag = 0;
}
/**
* 日志主键
*/
private long id;
/**
* 事务组Id
*/
private String groupId;
/**
* 日志sql
*/
private String sql;
/**
* 执行时间
*/
private long time;
/**
* 日志标示
* 0 业务执行的sql
* 1 框架添加的sql
*/
private int flag;
public Object[] params() {
Object[] arrays = new Object[]{id,groupId,sql,time,flag};
return arrays;
}
}
package com.codingapi.txlcn.tc.jdbc.log;
import org.apache.commons.dbutils.QueryRunner;
import java.sql.Connection;
import java.sql.SQLException;
/**
* @author lorne
* @date 2020/7/1
* @description
*/
public class TransactionLogExecutor {
private LogExecutor logExecutor;
private QueryRunner queryRunner = new QueryRunner();
public TransactionLogExecutor(LogExecutor logExecutor) {
this.logExecutor = logExecutor;
}
public void insert(Connection connection,TransactionLog transactionLog) throws SQLException {
String sql = logExecutor.insert(transactionLog);
queryRunner.execute(connection,sql,transactionLog.params());
}
public void delete(Connection connection,long id)throws SQLException{
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册