Java for Web学习笔记(一一一):再谈Entity映射(4)动态表格创建
2018-02-24 08:59
465 查看
如果这个不确定表格也需要我们的war来创建,如何实现。create table的原生SQL,entityManager是无法执行的,因为这不是可以回滚的事务。这种情况,我们需要:
捕获表格不存在的异常
从原始的Connection中实现表格创建。
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相关文章
捕获表格不存在的异常
从原始的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相关文章
相关文章推荐
- Java for Web学习笔记(一一二):再谈Entity映射(5)原生SQL和isolation
- Java for Web学习笔记(六一):Controller替代Servlet(3)body映射到参数
- Java for Web学习笔记(二三):EL(3)EL的视图
- Java for Web学习笔记(二六):JSTL(2)Core Tag(上)
- JAVA学习中使用Eclipse创建一个动态的WEB项目
- Java for Web学习笔记(二十):Session(4)在集群中使用Session
- Java for Web学习笔记(四四):WebSocket(1)演化历程
- Java for Web学习笔记(四五):WebSocket(2)JavaScript Client
- Java for Web学习笔记(二九):JSTL(5)FMT Tag(上)
- JAVA学习中使用Eclipse创建一个动态的WEB项目
- Java for Web学习笔记(四十):Filter(2)AsyncContext和Filter
- Java for Web学习笔记(八):Servlet(6)doGet()和doPost()是线程还是队列
- Java for Web学习笔记(四一):Filter(3)用于Log
- Java Web 学习笔记(四) 基于 SpringMVC+BootStrap 创建WebApp
- Java for Web学习笔记(十四):JSP(4)JSP Tag
- Java for Web学习笔记(六):Servlet(4)HttpServletResponse
- Java for Web学习笔记(四六):WebSocket(3)Java Server
- Java for Web学习笔记(二):Web Containers
- Java for Web学习笔记(二八):JSTL(4)Core Tag(下)
- Java for Web学习笔记(二一):EL(1)什么是EL