How to execute custom sql code in every transactio

2019-07-18 16:43发布

问题:

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.