2

我正在从事的一个项目使用具有行级安全性的 Oracle 数据库。call DBMS_APPLICATION_INFO.SET_CLIENT_INFO('userId');在执行任何其他 SQL 语句之前,我需要能够调用。我试图找出一种在 MyBatis 中实现这一点的方法。我有几个想法,但无法实现,包括以下内容:

尝试 1

<select id="selectIds" parameterType="string" resultType="Integer">
      call DBMS_APPLICATION_INFO.SET_CLIENT_INFO(#{userId});
    select id from FOO
</select>

但是,您不能在单个 JDBC 调用中使用两条语句,而且 MyBatis 不支持 JDBC 批处理语句,或者至少我找不到。

尝试 2

<select id="selectMessageIds" parameterType="string" resultType="Integer">
    <![CDATA[
        declare
           type ID_TYP is table of AGL_ID.ID_ID%type;
           ALL_IDS ID_TYP;
        begin
           DBMS_APPLICATION_INFO.SET_CLIENT_INFO(#{userId});
           select ID bulk collect
             into ALL_IDS
             from FOO
        end;
    ]]>
</select>

但是,这就是我所得到的,因为我了解到您不能在过程中返回数据,只能在函数中返回,因此无法返回数据。

尝试 3

我考虑过创建一个简单的 MyBatis 语句来设置客户端信息,并且需要在执行语句之前调用它。这似乎是最有希望的,但是,我们正在使用 Spring 和数据库连接池,我担心竞争条件。我想确保客户端信息不会溢出并影响其他语句,因为连接不会关闭,它们会被重用。

软件/框架版本信息

Oracle 10g
MyBatis 3.0.5
Spring 3.0.5

更新
忘了提我也在使用 MyBatis Spring 1.0.1

4

2 回答 2

2

这听起来像是交易的完美候选者。您可以创建@Transactional调用 DBMS_APPLICATION 函数的服务(或 DAO)基类。您的所有其他服务类都可以扩展基础并调用必要的 SQL。

在基类中,您要确保只调用 DBMS_APPLICATION 函数一次。为此,请使用TransactionSynchronizationManager.hasResource()bindResource()方法将布尔值或类似标记值绑定到当前 TX。检查此值以确定是否需要进行函数调用。

如果函数调用仅存在于数据库中的“工作单元”,那么这应该就是您所需要的。如果在连接期间存在调用,则基类将需要在 finally 块中以某种方式进行清理。

除了基类,另一种可能性是使用 AOP 并在方法调用之前进行函数调用,并将清理作为最终建议。这里的关键是确保在 Spring 的 TransactionInterceptor 之后调用您的拦截器(即在 tx 启动之后)。

于 2011-08-01T15:08:38.123 回答
0

最安全的解决方案之一是使用特定的DatSourceUtils

1http : //static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/jdbc/datasource/DataSourceUtils.html并覆盖doGetConnection(DataSource dataSource)和setClientInfo连接

在SqlMapClientDaoSupport上编写您自己的抽象来传递客户端信息。

于 2011-07-29T06:56:41.507 回答