您的位置:首页 > 编程语言 > Java开发

Java for Web学习笔记(一一一):再谈Entity映射(4)动态表格创建

2018-02-24 08:59 465 查看
如果这个不确定表格也需要我们的war来创建,如何实现。create table的原生SQL,entityManager是无法执行的,因为这不是可以回滚的事务。这种情况,我们需要:
捕获表格不存在的异常
从原始的Connection中实现表格创建。

获取Connection

能否从EntityManage中获取Connection依赖于JPA的具体实现,Eclipse的是支持,但是Hibernate不支持。
//可以通过unwrap来获取,可惜Hibernate不支持
Connection conn = entityManager.unwrap(Connection.class);
//如果我们需要使用Hibernate私有的api,可以利用unwrap()获取Hibernate的session
Session session = entityManager.unwrap(Session.class);
此路不通,我们需要从DataSource中获取。

在需要创建表格时抛出异常

public class WantCreateTableException extends RuntimeException{

private static final long serialVersionUID = 1L;

public WantCreateTableException(String message) {
super(message);
}
}

修改仓库的代码

@Repository
@Validated
public class EventRepository {
private static final Logger log = LogManager.getLogger();
private static final Gson gson = new Gson();
@PersistenceContext private EntityManager entityManager;
@Inject private DataSource dataSource;

private static final String CREATE_TABLE_SQLFORMAT = "CREATE TABLE IF NOT EXISTS `%s`("
+ "`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,"
+ "`data` text,"
+  "PRIMARY KEY (`id`)"
+ ")ENGINE=InnoDB DEFAULT CHARSET=utf8";
public void createTable(String tableName){
String sql = String.format(CREATE_TABLE_SQLFORMAT, tableName);
try(Connection conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);){
ps.execute();
}catch(SQLException e){
log.error("(SQL ERROR) Try to create table {} error : {}", tableName, e.toString());
}
}

private String getTableName(){
... ...
}

public EventData findOne(Long id) {
log.traceEntry();
String tableName = getTableName();
try{
String sql = String.format("SELECT * FROM `%s` WHERE `id`=?", tableName,id);
return  EventData.build((EventEntity) entityManager.createNativeQuery(sql,EventEntity.class)
.setParameter(1, id).getSingleResult());
}catch(Exception e){
return null;
}
}

public void save(EventData event) {
try{
if(event.getId() == null || event.getId() == 0)
this.insert(event);
else
this.update(event);
}catch(Exception e){
if(isTableNotExist(e, getTableName()))
throw new WantCreateTableException(getTableName());
else
throw e;
}
}

private boolean update(EventData data) {
... ...
}

private void insert(EventData data) {
... ...
}

private boolean isTableNotExist(Exception e,String tableName){
if(e.getCause() == null || e.getCause().getCause() == null)
return false;
String message = e.getCause().getCause().getMessage();
return StringUtils.contains(message, tableName.concat("' doesn't exist"));
}

}

使用例子

@Service
public class TestService {
@Transactional
public void test2(){
EventData event = new EventData();
event.addData("Hello,world!");
this.eventRepository.save(event);
}
}
下面只是测试例子,我们在controller中调用了仓库,这样做实际不好,controller应只调用Service,我们可以在中间有一个业务逻辑service,其调用TestService来完成相关的处理。@Transactional将在遇到RuntimeException是退出事务,而事务是采用proxy的方式,即本类内部调用是不起作用的。@Controller
public class TestController {
@Inject TestPageService testService;
@Inject EventRepository eventRepository;
private void mytest(){
try{
testService.test2();
}catch(WantCreateTableException e){
this.eventRepository.createTable(e.getMessage());
testService.test2();
}
}
}我尝试如下写,但失败了。//这个没有作用,仍然会报告Transaction was marked for rollback only; cannot commit;
//我的理解是WantCreateTableException只是我封装后的异常,还有本源的异常,已经在hibernate底层触发了rollback:
//严重: Servlet.service() for servlet [springWebDispatcher] in context with path [/chapter22] threw exception
// [Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException:
// Transaction was marked for rollback only; cannot commit; nested exception is org.hibernate.TransactionException:
// Transaction was marked for rollback only; cannot commit] with root cause
@Transactional(noRollbackFor = WantCreateTableException.class)
public void test2(){
EventData event = new EventData();
event.addData("Hello,world!");
try{
this.eventRepository.save(event);
}catch(WantCreateTableException e){
this.eventRepository.createTable(e.getMessage());
this.eventRepository.save(event);
}
}相关链接:我的Professional Java for Web Applications相关文章
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: