`

Atomikos+jdbcdslog——分布式事务管理输出实际log日志

阅读更多

前言

    想看实际产生的SQL,在一个数据源的情况下,最简单的方式是使用Log4jdbc。

    但在spring-data-jpa通过Atomikos实现JTA事务中,我们通过Atomikos实现了分布式事务,配置的是支持XA的DataSource,Log4jdbc这种在Driver上做文章的方法肯定不行。

    这里使用jdbcdslog的衍生项目jdbcdslog-exp来实现这个目标。jdbcdslog-exp比jdbcdslog更进了一步,输出的SQL,可以直接拷贝到PL/SQL等工具下执行。

 

依赖

jdbcdslog的依赖如下

<dependency>
    <groupId>com.googlecode.usc</groupId>
    <artifactId>jdbcdslog</artifactId>
    <version>1.0.6.2</version>
</dependency>

 

配置方式

properties配置信息

这里以Oracle为例,properties内容如下,当然dataSource配置信息等需要两份

 

dev.jdbc.dataSource=org.jdbcdslog.ConnectionPoolXADataSourceProxy
dev.jdbc.url=jdbc:oracle:thin:@192.168.3.129:1521:gtf?targetDS=oracle.jdbc.xa.client.OracleXADataSource
dev.jdbc.username=adp_dev
dev.jdbc.password=adp_dev

 其中url相当于url + targetDS ,targetDS的值为普通方式下的dataSource。

 

配置文件

一个数据源的配置方式如下,另一个同理。其它配置参照spring-data-jpa通过Atomikos实现JTA事务

 

<bean id="dataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init"
    destroy-method="close">
    <property name="uniqueResourceName" value="XA1DBMS" />
    <property name="xaDataSourceClassName" value="${dev.jdbc.dataSource}" />
    <property name="xaProperties">
        <props>
            <prop key="URL">${dev.jdbc.url}</prop>
            <prop key="user">${dev.jdbc.username}</prop>
            <prop key="password">${dev.jdbc.password}</prop>
        </props>
    </property>
    <property name="poolSize" value="10" />
    <property name="minPoolSize" value="10" />
    <property name="maxPoolSize" value="30" />
</bean>

 

 

问题

实际运行时会发生错误,原因是由于AtomikosDataSourceBean中doInit方法中在该方法的最后才调用的PropertyUtils.setProperties(xaDataSource, xaProperties );这段代码,导致上面调用setLogWriter的时候缺少参数。

 

解决方法

1.提供一个无视set/get方法的反射工具;

2.AtomikosDataSourceBean中用到的参数AtomikosXAConnectionFactory 没有访问修饰符,无法访问的问题;

 3.重新实现一个AtomikosDataSourceBean类,并重写doInit方法。

 

(1)set/get方法的反射工具

 

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

/**
 * 反射工具类.
 * 
 * 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
 * 
 * @author calvin
 */
public class Reflections {

	private static Logger logger = LoggerFactory.getLogger(Reflections.class);

    /**
     * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
     */
    public static Object getFieldValue(final Object obj, final String fieldName) {
        Field field = getAccessibleField(obj, fieldName);

        if (field == null) {
            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
        }

        Object result = null;
        try {
            result = field.get(obj);
        } catch (IllegalAccessException e) {
            logger.error("不可能抛出的异常{}", e.getMessage());
        }
        return result;
    }

    /**
     * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
     *
     * 如向上转型到Object仍无法找到, 返回null.
     */
    public static Field getAccessibleField(final Object obj, final String fieldName) {
        Validate.notNull(obj, "object can't be null");
        Validate.notBlank(fieldName, "fieldName can't be blank");
        for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
            try {
                Field field = superClass.getDeclaredField(fieldName);
                makeAccessible(field);
                return field;
            } catch (NoSuchFieldException e) {//NOSONAR
                // Field不在当前类定义,继续向上转型
            }
        }
        return null;
    }

    /**
     * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
     */
    public static void makeAccessible(Field field) {
        if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier
                .isFinal(field.getModifiers())) && !field.isAccessible()) {
            field.setAccessible(true);
        }
    }
}

 

(2)MyAtomikosXAConnectionFactory

解决自定义的AtomikosDataSourceBean无法访问问题,创建一个MyAtomikosXAConnectionFactory类,代码同AtomikosXAConnectionFactory完全一致;

 

 

(3)MyAtomikosDataSourceBean的doInit()方法

 

    protected com.atomikos.datasource.pool.ConnectionFactory doInit() throws Exception {
        if (xaDataSource == null) {
            if (xaDataSourceClassName == null)
                throwAtomikosSQLException("Property 'xaDataSourceClassName' cannot be null");
            if (xaProperties == null)
                throwAtomikosSQLException("Property 'xaProperties' cannot be null");
        }

        if (LOGGER.isInfoEnabled())
            LOGGER.logInfo(this + ": initializing with [" + " xaDataSourceClassName=" + xaDataSourceClassName
                    + "," + " uniqueResourceName=" + getUniqueResourceName() + "," + " maxPoolSize="
                    + getMaxPoolSize() + "," + " minPoolSize=" + getMinPoolSize() + ","
                    + " borrowConnectionTimeout=" + getBorrowConnectionTimeout() + "," + " maxIdleTime="
                    + getMaxIdleTime() + "," + " reapTimeout=" + getReapTimeout() + ","
                    + " maintenanceInterval=" + getMaintenanceInterval() + "," + " testQuery="
                    + getTestQuery() + "," + " xaProperties=" + printXaProperties() + "," + " loginTimeout="
                    + getLoginTimeout() + "," + " maxLifetime=" + getMaxLifetime() + "]");

        if (xaDataSource == null) {
            Class xadsClass = null;
            try {
                xadsClass = ClassLoadingHelper.loadClass(getXaDataSourceClassName());
            } catch (ClassNotFoundException nf) {
                AtomikosSQLException
                        .throwAtomikosSQLException(
                                "The class '"
                                        + getXaDataSourceClassName()
                                        + "' specified by property 'xaDataSourceClassName' could not be found in the classpath. Please make sure the spelling is correct, and that the required jar(s) are in the classpath.",
                                nf);

            }
            Object driver = xadsClass.newInstance();
            if (!(driver instanceof XADataSource)) {
                AtomikosSQLException
                        .throwAtomikosSQLException("The class '"
                                + getXaDataSourceClassName()
                                + "' specified by property 'xaDataSourceClassName' does not implement the required interface javax.jdbc.XADataSource. Please make sure the spelling is correct, and check your JDBC driver vendor's documentation.");
            }
            xaDataSource = (XADataSource) driver;
            PropertyUtils.setProperties(xaDataSource, xaProperties);
            ConnectionPoolXADataSourceProxy proxy = (ConnectionPoolXADataSourceProxy) xaDataSource;
            XADataSource targetDs = (XADataSource) Reflections.getFieldValue(proxy, "targetDS");
            targetDs.setLoginTimeout(getLoginTimeout());
            // xaDataSource.setLoginTimeout ( getLoginTimeout() );
            targetDs.setLogWriter(getLogWriter());
        }

        JdbcTransactionalResource tr = new JdbcTransactionalResource(getUniqueResourceName(), xaDataSource);
        com.atomikos.datasource.pool.ConnectionFactory cf = new MyAtomikosXAConnectionFactory(xaDataSource,
                tr, this);
        Configuration.addResource(tr);

        return cf;
    }

 

(4)logback配置文件

 

 

<logger name="org.jdbcdslog.ConnectionLogger" level="INFO" />
<logger name="org.jdbcdslog.StatementLogger" level="INFO" />
<logger name="org.jdbcdslog.ResultSetLogger" level="INFO" />

看名就知道输出的是哪一部分数据,如果只看SQL,用org.jdbcdslog.StatementLogger就够了。
 

至此,Atomikos+jdbcdslog配置成功

0
0
分享到:
评论

相关推荐

    spring+atomikos+druid分布式事务

    使用spring + atomikos+druid配置的分布式事务demo,两种数据源配置方式都可以,使用junit测试没问题,案例中使用的mysql数据库是8.0.11版本,版本不同请自行修改pom.xml和jdbc.properties

    spring+atomikos+druid分布式事务Demo

    本示例"spring+atomikos+druid分布式事务Demo"聚焦于如何在Spring框架中利用Atomikos和Druid来处理分布式事务。接下来,我们将深入探讨这三个组件以及它们在实现分布式事务中的作用。 Spring是一个广泛使用的Java...

    Spring3.0+Hibernate+Atomikos多数据源分布式事务管理

    本教程将聚焦于如何利用Spring 3.0、Hibernate ORM框架以及Atomikos这个开源事务管理器来实现高效、可靠的多数据源分布式事务处理。 **Spring 3.0**: Spring是Java开发中最广泛使用的轻量级框架之一,它提供了一个...

    Spring boot+Atomikos+JTA+Hibernate+mybatis+MySQL实现分布式事务+多数据源

    Atomikos是一款开源的JTA事务管理器,它支持分布式事务处理,使得在多个数据源之间进行事务操作成为可能。JTA是Java平台中的标准API,用于管理跨越多个资源(如数据库或消息队列)的事务。Atomikos通过实现JTA规范,...

    使用Spring+atomikos实现分布式事务

    Spring框架提供了强大的支持来处理分布式事务,而Atomikos是一个开源的事务管理器,专门用于处理JTA(Java Transaction API)事务,尤其适用于微服务和分布式环境。本教程将探讨如何结合Spring和Atomikos来实现...

    Springboot+Atomikos+Jpa+Mysql实现JTA分布式事务

    在分布式事务场景中,MySQL作为数据存储,需要与事务管理器Atomikos配合,共同保证事务的正确性。 要实现Spring Boot、Atomikos、JPA和MySQL的集成,你需要进行以下步骤: 1. 添加依赖:在Spring Boot的`pom.xml`...

    SpringBoot+Mybatis+Atomikos+Mysql+Oracle 多数据源分布式事物后台搭建

    SpringBoot+Mybatis+Atomikos+Mysql+Oracle 多数据源分布式事物后台搭建 完整demo包,直接下下来解压,数据库配成自己的库,表自己的表,修改下脚本直接跑,网上大把资料,没一个能直接用的,这里花了点时间稍做...

    Spring boot+Atomikos+JTA+Hibernate+MySQL实现分布式事务+多数据源(可运行)

    本项目使用Spring Boot、Atomikos、JTA(Java Transaction API)、Hibernate和MySQL来实现分布式事务处理和多数据源管理,以确保在多个数据库操作之间保持事务的ACID特性。 首先,Spring Boot作为微服务开发的主流...

    java+spring+mybatis+mysql+RuoYi-atomikos-实现分布式事务.zip

    本项目"java+spring+mybatis+mysql+RuoYi-atomikos-实现分布式事务.zip"是一个基于若依(RuoYi)框架改造的多模块分布式事务解决方案,它利用了Atomikos这一强大的分布式事务管理器。以下将详细解析这个项目的知识点...

    spring + JTA + atomikos 实现分布式事务

    总之,Spring + JTA + Atomikos的组合提供了一种强大而灵活的方式,用于处理分布式环境中的事务管理。通过理解JTA的基本原理,掌握Spring的事务管理机制,以及熟悉Atomikos的使用,开发者可以构建出高可用、强一致性...

    springboot + mybatis + atomikos 多数据源分布式事物管理

    Git 版本控制的文件、Atomikos 事务日志锁文件、事务日志文件、Maven 命令行脚本、Eclipse 项目配置、Maven 的 POM 配置文件以及项目构建输出目录。这些文件共同构成了一个标准的 Spring Boot 项目结构,其中 `pom....

    spring4+atomikos实现分布式事务

    至于`demo4.ini`文件,这可能是Atomikos的配置文件,其中包含了Atomikos如何初始化和配置事务管理器的详细信息,例如日志位置、最大并发事务数等。配置文件的具体内容因项目需求而异,但通常会包括以下部分: ```...

    非Maven基于SSM+Atomikos的分布式事务处理案例源码

    SSM(SpringMVC、Spring、MyBatis)框架是Java Web开发中常见的技术栈,而Atomikos则是一个强大的开源事务管理器,主要用于处理分布式事务。本案例以非Maven方式构建,展示了如何在不依赖Maven构建系统的情况下,...

    SpringBoot+Atomikos分布式事务及多数据源动态切换,两种demo

    Spring Boot作为轻量级的Java开发框架,结合Atomikos这样的分布式事务管理器,可以有效地解决这些问题。本文将深入探讨如何在Spring Boot项目中实现Atomikos分布式事务以及动态数据源切换的两种示例。 首先,我们...

    spring搭建分布式事务所需嘉宝atomikos加druid配置分布式事务

    Spring框架提供了多种实现分布式事务管理的方式,其中一种是通过集成第三方工具如Atomikos来实现。Atomikos是一个开源的事务处理服务,支持JTA(Java Transaction API),能很好地处理分布式环境中的ACID(原子性、...

    Spring中使用atomikos+druid实现经典分布式事务的方法

    Spring 中使用 Atomikos+Druid 实现经典分布式事务的方法 在分布式系统中,经典分布式事务是相对互联网中的柔性分布式事务而言,其特性为 ACID 原则,包括原子性(Atomictiy)、一致性(Consistency)、隔离性...

    SpringBoot+mybatisPlus+atomikos+druid.zip

    Spring Boot:mybatis-plus + atomikos + druid 实现不同实例数据库的多数据源配置和分布式事务管理(demo项目),想到工作上可能会用到多数据源,但是自己在这方面并不是很熟悉,于是在网上查阅了很多文章,结果...

    基于Spring4.1.7+atomikos+mybaits 实现两阶段的分布式事务处理

    我们需配置Atomikos的事务管理器,并将其集成到Spring中,使得MyBatis的SQL操作能够在分布式事务的上下文中进行。 具体实现步骤如下: 1. 引入相关依赖:包括Spring、Atomikos和MyBatis的库,以及可能的数据库驱动...

    Spring4.1.7+atomikos+mybaits 实现两阶段的分布式事务处理

    将基于Spring4.1.7+atomikos+mybaits 实现两阶段的分布式事务处理,通过AOP面向切面实现动态实现数据源的切换 http://www.dczou.com/viemall/407.html

    SpringBoot+Atomikos+动态多数据源+事务+2种切换数据源的方式

    本主题将深入探讨如何利用SpringBoot结合Atomikos实现动态多数据源以及事务管理,并介绍两种切换数据源的方法。 首先,SpringBoot简化了传统Spring应用的初始化过程,它通过自动配置和starter包让开发者快速搭建...

Global site tag (gtag.js) - Google Analytics