2011-02-12 66 views
2

我是一个很长时间的读者,第一次海报。春天jpa安装程序无法更新数据库

基本上我正在编写一个基于spring 3 showcase的web应用程序。

随后我插入基于this tutorial写入数据库的功能。

我的集成测试测试所有的ORM东西显得很开心,但是当我将项目部署到tomcat并尝试通过网站进行数据库更新时数据库没有更新!

配置:

appContext.xml

<!-- holding properties for database connectivity/--> 
<context:property-placeholder location="classpath:jdbc.properties" /> 
<!-- enabling annotation driven configuration/--> 
<context:annotation-config /> 
<context:component-scan base-package="wcpackage" /> 
<tx:annotation-driven transaction-manager="transactionManager" /> 

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> 

<bean id="dataSource" 
    class="org.springframework.jdbc.datasource.DriverManagerDataSource" 
    p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" /> 

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" 
    p:entityManagerFactory-ref="entityManagerFactory" /> 

<bean id="entityManagerFactory" 
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" 
    p:dataSource-ref="dataSource" p:jpaVendorAdapter-ref="jpaAdapter"> 
    <property name="loadTimeWeaver"> 
     <bean 
      class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" /> 
    </property> 
    <property name="persistenceUnitName" value="wctemplatePU"></property> 
</bean> 

<bean id="jpaAdapter" 
    class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" 
    p:showSql="${jpa.showSql}" /> 

jdbc.properties

jpa.database=gm 
jpa.showSql=true 
jdbc.driverClassName=com.mysql.jdbc.Driver 
jdbc.url=jdbc:mysql://localhost:3306/gm?user=gmuser&password=gmuser 

的persistence.xml

<persistence xmlns="http://java.sun.com/xml/ns/persistence" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence"> 

<persistence-unit name="wctemplatePU" transaction-type="RESOURCE_LOCAL"> 
    <properties> 
     <property name="hibernate.hbm2ddl.auto" value="validate" /> 
    </properties> 
</persistence-unit> 

应该提交到数据库

@Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class) 
protected Sequence persistGame(PGNGame game) { 
    Sequence seq = new Sequence(); 
    seq.setType(SequenceType.GAME); 
    seq.setEvent(game.getTag("Event")); 
    seq.setSite(game.getTag("Site")); 

      ... 

    sequenceDao.persist(seq); 

    return seq; 
} 

SequenceDao

代码基本上

public abstract class JpaDao<K, E> implements Dao<K, E> { 
protected Class<E> entityClass; 

@PersistenceContext 
protected EntityManager entityManager; 

public JpaDao() { 
    ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass(); 
    this.entityClass = (Class<E>) genericSuperclass.getActualTypeArguments()[1]; 
} 

public void persist(E entity) { entityManager.persist(entity); } 

public void remove(E entity) { entityManager.remove(entity); } 

public E findById(K id) { return entityManager.find(entityClass, id); } 
} 

我拿不出任何形式,我可以在控制台/看到日志的错误。我究竟做错了什么?

有一件事我注意到,当我杀青休眠调试日志

DEBUG:org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler - Creating new EntityManager for shared EntityManager invocation 
    DEBUG: org.hibernate.impl.SessionImpl - opened session at timestamp: 12975078282 
    DEBUG: org.hibernate.event.def.AbstractSaveEventListener - delaying identity-insert due to no transaction in progress 
    DEBUG: org.hibernate.event.def.AbstractSaveEventListener - delaying identity-insert due to no transaction in progress 
    DEBUG: org.springframework.orm.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager 

跟踪日志

DEBUG:org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler - Creating new EntityManager for shared EntityManager invocation 
DEBUG: org.hibernate.impl.SessionImpl - opened session at timestamp: 12975085724 
TRACE: org.hibernate.engine.IdentifierValue - id unsaved-value: 0 
TRACE: org.hibernate.event.def.AbstractSaveEventListener - transient instance of: net.samuelbergin.gm.model.Player 
TRACE: org.hibernate.event.def.DefaultPersistEventListener - saving transient instance 
TRACE: org.hibernate.event.def.AbstractSaveEventListener - saving [net.samuelbergin.gm.model.Player#<null>] 
TRACE: org.hibernate.engine.Cascade - processing cascade ACTION_PERSIST_SKIPLAZY for: net.samuelbergin.gm.model.Player 
TRACE: org.hibernate.engine.Cascade - done processing cascade ACTION_PERSIST_SKIPLAZY for: net.samuelbergin.gm.model.Player 
TRACE: org.hibernate.event.def.WrapVisitor - Wrapped collection in role: net.samuelbergin.gm.model.Player.sequenceList 
DEBUG: org.hibernate.event.def.AbstractSaveEventListener - delaying identity-insert due to no transaction in progress 
TRACE: org.hibernate.engine.Cascade - processing cascade ACTION_PERSIST_SKIPLAZY for: net.samuelbergin.gm.model.Player 
TRACE: org.hibernate.engine.Cascade - cascade ACTION_PERSIST_SKIPLAZY for collection: net.samuelbergin.gm.model.Player.sequenceList 
TRACE: org.hibernate.engine.CascadingAction - cascading to persist: net.samuelbergin.gm.model.Sequence 
TRACE: org.hibernate.engine.IdentifierValue - id unsaved-value: 0 
TRACE: org.hibernate.event.def.AbstractSaveEventListener - transient instance of: net.samuelbergin.gm.model.Sequence 
TRACE: org.hibernate.event.def.DefaultPersistEventListener - saving transient instance 
TRACE: org.hibernate.event.def.AbstractSaveEventListener - saving [net.samuelbergin.gm.model.Sequence#<null>] 
TRACE: org.hibernate.engine.Cascade - processing cascade ACTION_PERSIST_SKIPLAZY for: net.samuelbergin.gm.model.Sequence 
TRACE: org.hibernate.engine.Cascade - done processing cascade ACTION_PERSIST_SKIPLAZY for: net.samuelbergin.gm.model.Sequence 
TRACE: org.hibernate.event.def.WrapVisitor - Wrapped collection in role: net.samuelbergin.gm.model.Sequence.commentList 
TRACE: org.hibernate.engine.IdentifierValue - id unsaved-value: 0 
DEBUG: org.hibernate.event.def.AbstractSaveEventListener - delaying identity-insert due to no transaction in progress 
TRACE: org.hibernate.engine.Cascade - processing cascade ACTION_PERSIST_SKIPLAZY for: net.samuelbergin.gm.model.Sequence 
TRACE: org.hibernate.engine.Cascade - cascade ACTION_PERSIST_SKIPLAZY for collection: net.samuelbergin.gm.model.Sequence.commentList 
TRACE: org.hibernate.engine.Cascade - done cascade ACTION_PERSIST_SKIPLAZY for collection: net.samuelbergin.gm.model.Sequence.commentList 
TRACE: org.hibernate.engine.Cascade - done processing cascade ACTION_PERSIST_SKIPLAZY for: net.samuelbergin.gm.model.Sequence 
TRACE: org.hibernate.engine.Cascade - done cascade ACTION_PERSIST_SKIPLAZY for collection: net.samuelbergin.gm.model.Player.sequenceList 
TRACE: org.hibernate.engine.Cascade - done processing cascade ACTION_PERSIST_SKIPLAZY for: net.samuelbergin.gm.model.Player 
DEBUG: org.springframework.orm.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager 
TRACE: org.hibernate.impl.SessionImpl - closing session 

实体定义

@Entity 
@Table(name="sequences") 
public class Sequence { 
    @Id 
    @GeneratedValue 
    private int id; 
    @Enumerated(EnumType.STRING) 
    private SequenceType type; 
    private String event; 
    private String site; 
    @Temporal(TemporalType.DATE) 
    private Date date; 
    private int round; 
    private String result; 
    private String eco; 
    private String description; 
    private String moves; 
    @ManyToOne 
    private Player whitePlayer; 
    @ManyToOne 
    private Player blackPlayer; 
    @OneToMany(cascade={CascadeType.ALL}) 
    @JoinTable(name="sequenceComments", 
      joinColumns={@JoinColumn(name="sequence_fk")}, 
      inverseJoinColumns={@JoinColumn(name="comment_fk")}) 
    private List<Comment> commentList = new ArrayList<Comment>(); 
     ... 

控制器

@Controller 
@RequestMapping("/fileupload") 
public class FileUploadController { 

    private static Logger logger = LoggerFactory.getLogger(FileUploadController.class); 

    @Autowired private SequenceService sequenceService; 

    @RequestMapping(method=RequestMethod.POST) 
    public void processUpload(@RequestParam MultipartFile file, HttpServletRequest request, Model model) throws IOException { 
     //TODO: parse pgn 
     List<PGNGame> pgnGameList; 
     String filename = file.getOriginalFilename(); 
     try { 
      pgnGameList = PGNProcessor.parse(file.getInputStream()); 

      sequenceService.createSequences(pgnGameList); 

      String message = "File '" + filename + "' uploaded successfully"; 
      model.addAttribute("message", new Message(MessageType.success, message)); 

     } catch (PGNProcessorException ppe) { 
      logger.error("Failed to process "+filename, ppe); 
      model.addAttribute("message", new Message(MessageType.error, "Failed to process "+filename+". Reason: "+ppe.getMessage())); 
     } 
     // else whole html pg is rendered instead of just a div to update 
     model.addAttribute("ajaxRequest", AjaxUtils.isAjaxUploadRequest(request)); 
    } 
} 

服务

public class JpaSequenceService implements SequenceService { 

    ... 

public List<Sequence> createSequences(List<PGNGame> gameList) { 
    List<Sequence> seqList = new ArrayList<Sequence>(); 
    for (PGNGame game : gameList) { 
     Sequence seq = persistGame(game); 
     seqList.add(seq); 
    } 
    return seqList; 
} 

@Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class) 
protected Sequence persistGame(PGNGame game) { 
     /*...as above...*/ 
} 
+0

什么叫'persistGame()`方法? – skaffman 2011-02-12 10:49:39

+0

是的,这绝对是所谓的。我的控制器注入一个包含persistGame()方法的服务。 – SamB 2011-02-12 10:53:58

回答

3

@Transactional只有当其放置在从其他对象调用(而不是在同一对象)的公共方法的工作原理。

通过在对象周围创建代理来处理事务。代理拦截来自外部的呼叫,因此交易开始。代理不拦截同一对象内的调用。

所以你的情况:

@Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class) 
public List<Sequence> createSequences(List<PGNGame> gameList) { 

注意,它通常是一种很好的做法,在事务内包的工作单元。即使您的代码正常工作,也会不必要地打开和关闭多个事务。除非你想单独坚持每场比赛。如果是这种情况,那么在控制器中迭代列表,或者创建一个新的类来保存游戏。

由于奥古斯托指出,如果你使用proxy-target-class="true"你的代理,你可以做一个内部调用启动事务。不过,我不鼓励这样做,因为您正在依赖此配置选项,并且如果您出于其他原因而将来更改,则可能会浪费时间来查找为什么现有功能停止工作。