How to execute custom sql code in every transaction managed by spring DataSourceTransactionManager?

我的梦境 提交于 2019-12-12 18:12:12

问题


Consider situation in which we have tons of java DAO classes managed by Spring. Every method defined in those beans executes SQL code in Spring's Datasource transaction, defined by annotation on a method. Now we have a requirement to run some custom code just before target execution of mentioned methods, this code MUST be executed in the same transaction as defined by annotation on target method.

Update based on R4J comment:

My proxy for DAO calls which should call procedure PR_Adm_Set_Usr in transaction of every target call in DAO package:

@Aspect
@Order(1000)
@Component
public class DaoProxy {

    private static final Logger logger = LoggerFactory.getLogger(DaoProxy.class);
    @Autowired
    private ContextDAO contextDAO;
    @Autowired
    private DataSourceTransactionManager txManager;


   @Before("execution(* xx.yy.dao.*.*(..)) xx.yy.core.dao.*.*(..))")
    @Transactional(propagation = Propagation.SUPPORTS)
    public void setContext() throws Throwable {
        JdbcTemplate jdbc = new JdbcTemplate(txManager.getDataSource());
        if(SecurityContextHolder.getContext()!=null &&
                SecurityContextHolder.getContext().getAuthentication()!=null &&
                SecurityContextHolder.getContext().getAuthentication().getPrincipal()!=null){
            SimpleJdbcCall jdbcCall = new SimpleJdbcCall(jdbc)
                    .withProcedureName("PR_Adm_Set_Usr")
                    .withoutProcedureColumnMetaDataAccess().declareParameters(
                            new SqlParameter("user", OracleTypes.VARCHAR));
            jdbcCall.setAccessCallParameterMetaData(false);
            MapSqlParameterSource params = new MapSqlParameterSource()
                    .addValue("user",  SecurityContextHolder.getContext().getAuthentication().getName()  );
            jdbcCall.execute(params);
        }else{
            logger.warn("No context available!!!");
        }
    }
}

Example DAO call in SomeDAO class:

 @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public Object shiftDate(Long fileId, Long interval) {
        String a=null;
        a.toString();
        JdbcTemplate jdbc = new JdbcTemplate(txManager.getDataSource());
        SimpleJdbcCall jdbcCall = new SimpleJdbcCall(jdbc)
                .withCatalogName("somepackage")
                .withProcedureName("someprocedure")
                .withoutProcedureColumnMetaDataAccess()
                .declareParameters(
                        new SqlParameter("p_file_id", OracleTypes.NUMBER),
                        new SqlParameter("p_interval", OracleTypes.NUMBER)
                );
        jdbcCall.setAccessCallParameterMetaData(false);
        MapSqlParameterSource params = new MapSqlParameterSource()
                .addValue("p_file_id", fileId)
                .addValue("p_interval", interval);
        jdbcCall.execute(params);
        return null;

    }

As You can see, first two lines in DAO call cause NullPointerException, which should cause rollback on AOP setContext() method. Unfortunately this was not working till I added order to my tag in my context config.

<tx:annotation-driven order="1"/> solved the problem.

来源:https://stackoverflow.com/questions/33864586/how-to-execute-custom-sql-code-in-every-transaction-managed-by-spring-datasource

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!