如何将Oracle的行级安全性与MyBatis集成?

时间:2011-07-28 15:39:26

标签: oracle spring java-ee jdbc mybatis

我正在使用的项目和具有行级安全性的Oracle数据库。我需要能够在执行任何其他SQL语句之前调用call DBMS_APPLICATION_INFO.SET_CLIENT_INFO('userId');。我试图想出一种在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

2 个答案:

答案 0 :(得分:2)

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

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

如果函数调用只存在于DB中的“工作单元”,那么这应该就是您所需要的。如果在连接期间存在调用,那么基类在某种程度上需要在finally块中过于清理。

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

答案 1 :(得分:0)

最安全的解决方案之一是设置一个特定的DatSourceUtils

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

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