我想知道Hibernate或Spring或任何第三方lib是否能够将DBMS_OUTPUT.put_line消息直接打印到system.out或日志文件。
目的是在控制台中同时拥有PLSQL日志消息和Java日志消息。
我知道有一个类似的问题,答案是将PLSQL过程转换为返回日志消息的功能,但这并不适合我的情况。事实上,我的日志消息太复杂了,无法在函数中返回它。
我已阅读此https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:45027262935845并获得了灵感,但我想知道是否有一个开箱即用的解决方案来避免鲸鱼繁殖。
答案 0 :(得分:1)
由于没有人回答这个问题,我认为没有任何开箱即用的解决方案。因此,我自己构建并在此处发布我可能感兴趣的代码。
欢迎任何想要改进此解决方案的人!分享你的东西真是太可惜了!
基于Spring AOP的解决方案。创建注释@DbmsOutput
以在相关方法上添加DBMS_OUTPUT识别能力。
环境:Maven + Spring 4.2.6 + Hibernate 5.1.0
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.4</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.4</version>
</dependency>
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface DbmsOutput {
}
@DbmsOutput
声明的所有方法创建拦截器。import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.jdbc.Work;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
@Aspect
@Order(Ordered.LOWEST_PRECEDENCE)
public class DbmsOutputAspect {
private static final Logger LOGGER = Logger.getLogger(DbmsOutputAspect.class);
@Autowired
protected SessionFactory sessionFactory;
/**
* make Dbms output aware enable/disable configurable in spring bean declaration
*/
private boolean enable = true;
private int size = 1000000;
public boolean isEnable() {
return enable;
}
public void setEnable(final boolean enable) {
this.enable = enable;
}
public int getSize() {
return size;
}
public void setSize(final int size) {
this.size = size;
}
@Pointcut("execution(@DbmsOutput * *(..))")
public void DbmsOutputInterceptMethod() {
}
@Around("DbmsOutputInterceptMethod()")
public Object around(final ProceedingJoinPoint point)
throws Throwable {
if (isEnable()) {
LOGGER.debug("before DBMS_OUTPUT point cut");
Query queryEnable = sessionFactory.getCurrentSession().createSQLQuery("call dbms_output.enable(:size)");
queryEnable.setParameter("size", getSize());
queryEnable.executeUpdate();
}
try {
return point.proceed(point.getArgs());
} finally {
if (isEnable()) {
sessionFactory.getCurrentSession().doWork(new Work() {
@Override
public void execute(final Connection connection)
throws SQLException {
CallableStatement show_stmt = connection.prepareCall(
"declare " +
" l_line varchar2(255); " +
" l_done number; " +
" l_buffer long; " +
"begin " +
" loop " +
" exit when length(l_buffer)+255 > :maxbytes OR l_done = 1; " +
" dbms_output.get_line( l_line, l_done ); " +
" l_buffer := l_buffer || l_line || chr(10); " +
" end loop; " +
" :done := l_done; " +
" :buffer := l_buffer; " +
"end;");
int done = 0;
show_stmt.registerOutParameter(2, java.sql.Types.INTEGER);
show_stmt.registerOutParameter(3, java.sql.Types.VARCHAR);
for (;;) {
show_stmt.setInt(1, 32000);
show_stmt.executeUpdate();
LOGGER.info(show_stmt.getString(3));
done = show_stmt.getInt(2);
if (done == 1) {
break;
}
}
}
});
Query queryDisable = sessionFactory.getCurrentSession().createSQLQuery("call dbms_output.disable()");
queryDisable.executeUpdate();
LOGGER.debug("after DBMS_OUTPUT point cut");
}
}
}
}
DbmsOutputAspect
和TransactionManager
<!-- aspectj -->
<aop:aspectj-autoproxy proxy-target-class="true" />
<bean class="DbmsOutputAspect" />
<!-- transaction -->
<tx:annotation-driven transaction-manager="transactionManager" order="0" />
<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>