使用jOOQ 3.9.1我生成了Pojos,Daos,Records,Tables和验证。
一个UserService类,其中包含一个从test中调用的方法,该类为@Transactional。 这个服务被调用,它有Transactional所以一个事务启动,我创建一个新用户,同样的方法获取该新用户的id然后添加一个角色并调用该服务中的另一个方法来添加一个默认配额,它是在调试日志“尝试更改用户的配额”,我得到一个org.jooq.exception.NoDataFoundException(“预计刷新一行正好一行。数据库中不存在记录。”)。 似乎Dao没有重用相同的连接或相同的事务,因此它没有看到新用户,因为它尚未提交。
jOOQ有bug /问题吗?或者我配置错误了?
但是如果我用create覆盖一个对象的插入,它就没有任何问题,然后保留事务然后提交。 如果没有覆盖并为QuotaHistory中的插入传递2个对象(以及更多),则dao可以工作(请参阅jooq中的代码,无论传递的集合是否包含1个或更多元素,它都不会调用相同的方法)
public User createUser(String username, String login, String password, String email, String locale) {
if (!loginRegex.matcher(login).matches()) {
throw new IllegalArgumentException("Login does not match pattern");
}
final Role defaultRole = roleRepository.fetchOneByName(RoleConstants.USER);
final String salt = RandomUtil.generateSalt();
final Timestamp timestamp = dateTimeService.getCurrentTimestamp();
final User newUser = new User();
newUser.setLogin(login);
// ... others set here
userRepository.insert(newUser);
final User userInserted = userRepository.fetchOneByLogin(login);
userHasRoleRepository.insert(new UserHasRole(userInserted.getId(), defaultRole.getId()));
// This method call another method within the UserSevice, it simply insert a new row in another table for user quota with primary key the user id and the DateTime of the insert
// It calls the DAO generated by jOOQ
changeQuotaByLogin(newUser.getLogin(), applicationProperties.getUser().getQuotaDefault());
log.debug("Created User: {}", userInserted);
return userInserted;
}
public void changeQuotaByLogin(String login, int quota) {
Optional.ofNullable(userRepository.fetchOneByLogin(SecurityUtils.getCurrentUserLogin())).map(userLogged -> {
Optional.ofNullable(userRepository.fetchOneByLogin(login)).ifPresent(userToModify -> {
log.debug("Before create local UserQuotaHistory");
final UserQuotaHistory userQuotaHistory = new UserQuotaHistory(userToModify.getId(), dateTimeService.getCurrentTimestamp(), quota, userLogged.getId());
log.debug("Try to change quota for User: {} by {}", userToModify, userLogged);
userQuotaHistoryRepository.insert(userQuotaHistory);
userToModify.setUpdateTime(dateTimeService.getCurrentTimestamp());
userRepository.update(userToModify);
log.debug("Changed quota for User: {} by {}", userToModify, userLogged);
});
return userLogged;
}).orElseThrow(() -> {
log.error("Tried to change quota but no user logged, tried to modify {}", login);
return new IllegalStateException("There is no logged user");
});
}
为了保留daos,我只需要在我的存储库中传递一个扩展生成的dao的对象时覆盖插入。 Create是dsl的依赖注入。
@Repository
public class UserQuotaHistoryRepository extends UserQuotaHistoryDao {
private final DSLContext create;
@Autowired
public UserQuotaHistoryRepository(Configuration configuration, DSLContext create) {
super(configuration);
this.create = create;
}
@Override
public void insert(UserQuotaHistory u){
create.insertInto(USER_QUOTA_HISTORY)
.set(USER_QUOTA_HISTORY.USER_ID, u.getUserId())
.set(USER_QUOTA_HISTORY.CREATE_TIME, u.getCreateTime())
.set(USER_QUOTA_HISTORY.QUOTA, u.getQuota())
.set(USER_QUOTA_HISTORY.CHANGED_BY_USER_ID, u.getChangedByUserId())
.execute();
}
}
我的持久性配置:
@Configuration
@EnableTransactionManagement
public class PersistenceContextConfiguration {
private static final Logger log = LoggerFactory.getLogger(PersistenceContextConfiguration.class);
private Environment env;
@Autowired
public PersistenceContextConfiguration(Environment env) {
this.env = env;
}
@Bean(destroyMethod = "close")
@Primary
public DataSource dataSource() {
BoneCPDataSource dataSource = new BoneCPDataSource();
dataSource.setDriverClass(env.getRequiredProperty("db.driver"));
dataSource.setJdbcUrl(env.getRequiredProperty("db.url"));
dataSource.setUsername(env.getRequiredProperty("db.username"));
dataSource.setPassword(env.getRequiredProperty("db.password"));
try {
Connection connection = dataSource.getConnection();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
log.error(e.getMessage());
}
return dataSource;
}
@Bean
public LazyConnectionDataSourceProxy lazyConnectionDataSource() {
return new LazyConnectionDataSourceProxy(dataSource());
}
@Bean
public TransactionAwareDataSourceProxy transactionAwareDataSource() {
return new TransactionAwareDataSourceProxy(lazyConnectionDataSource());
}
@Bean
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(lazyConnectionDataSource());
}
@Bean
public DataSourceConnectionProvider connectionProvider() {
return new DataSourceConnectionProvider(transactionAwareDataSource());
}
@Bean
public JOOQToSpringExceptionTransformer jooqToSpringExceptionTransformer() {
return new JOOQToSpringExceptionTransformer();
}
@Bean
public DefaultConfiguration configuration() {
DefaultConfiguration jooqConfiguration = new DefaultConfiguration();
jooqConfiguration.set(connectionProvider());
jooqConfiguration.set(new DefaultExecuteListenerProvider(
jooqToSpringExceptionTransformer()
));
String sqlDialectName = env.getRequiredProperty("jooq.sql.dialect");
SQLDialect dialect = SQLDialect.valueOf(sqlDialectName);
jooqConfiguration.set(dialect);
return jooqConfiguration;
}
@Bean
public DefaultDSLContext dsl() {
return new DefaultDSLContext(configuration());
}
@Bean
public DataSourceInitializer dataSourceInitializer() {
DataSourceInitializer initializer = new DataSourceInitializer();
initializer.setDataSource(dataSource());
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
populator.addScript(
new ClassPathResource(env.getRequiredProperty("db.schema.script"))
);
initializer.setDatabasePopulator(populator);
return initializer;
}
}