V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
forreal
V2EX  ›  Java

spring 管理 hibernate 事务时,entity 类的主键必须设为 Long 或 Integer 吗?

  •  
  •   forreal · 2014-11-07 18:34:02 +08:00 · 7869 次点击
    这是一个创建于 3699 天前的主题,其中的信息可能已经有所发展或是发生改变。
    我之前写了一个entity类,@Id注解在String类型的name字段上。(因为就这一个字段,另外加一个id字段浪费)。
    然后当我session.save()时,不生成insert语句,也不插入数据库。除非我session.flush()一下才插入数据库。
    而当我把entity类增加一个Long类型的id字段并且设置自动增长时,再session.save()时,就既生成insert语句又插入字段。
    请问这是为什么呢?
    13 条回复    2014-11-10 13:20:26 +08:00
    welsmann
        1
    welsmann  
       2014-11-07 21:33:03 +08:00   ❤️ 1
    根据需要加入@GeneratedValue注解
    qping
        2
    qping  
       2014-11-07 22:29:59 +08:00   ❤️ 1
    下面是百度搜的,印象中是这样的。
    "session在什么情况下执行flush:默认在事务提交时;显示的调用flush;在执行查询前,如:iterate.
    调用save后,只是将对象纳入到了session的管理,不会发出insert语句,如没有主键会根据主键生成策略生成主键,把脱管或瞬态对象变为持久态对象."

    http://zhidao.baidu.com/link?url=p8o00ykbezRThHvydBXl3RvUZFO1cvOTB-XcD3m5I2K1idgOcSdTAP2GAC-xEaJOCe01G5S7mOSfMpzzvH5m-K
    shuson
        3
    shuson  
       2014-11-08 10:10:40 +08:00   ❤️ 1
    @GeneratedValue(strategy = GenerationType.AUTO) cannot be used with String type. A straightforward solution could be to use the @PrePersist annotation on your entity class.
    forreal
        4
    forreal  
    OP
       2014-11-08 17:26:08 +08:00
    @welsmann 主键我想自己指定,不想自动生成。但是我试了如果实体的主键是Long类型却不加@GeneratedValue 也会save()时不插入数据库。

    @qping 如果不加@GeneratedValue到主键上,commit()时就不会插入数据库。不知道为什么。(哪怕我手动指定了主键)

    @shuson 意思是先用自动生成主键,然后再@PrePersist注解的方法 改对象的主键吗?
    qping
        5
    qping  
       2014-11-08 19:23:44 +08:00
    有其他语句吗 比如update语句,没有错误日志,相关配置,只能等高手过来帮你猜了 - -
    qping
        6
    qping  
       2014-11-08 19:29:41 +08:00
    我始终不认为你错的地方在于注解GeneratedValue 或者 主键Long类型。
    事务提交后没有insert语句,应该是事务配置或者hibernate对象状态。

    http://www.baidu.com/s?wd=hibernate%E5%AF%B9%E8%B1%A1%E7%8A%B6%E6%80%81
    http://www.baidu.com/s?wd=hibernate%20%E4%B8%BB%E9%94%AE%E7%94%9F%E6%88%90

    我曾经因为spring mvc传递的是 持久态的对象,修改其主键后怎么改后台都是update,而我想要的是insert ,楼主看是不是这种情况
    forreal
        7
    forreal  
    OP
       2014-11-08 19:46:42 +08:00
    @qping 没有错误日志(控制台上sql语句,错误日志什么都没有),
    配置都是照https://github.com/ZhibingXie/SpringMVC-Spring-Hibernate来配的。
    就是有一个实体类,id用的是名字(String类型),而且没有注解@GeneratedValue,然后事务提交不发出insert语句也不存入数据库。必须手动调用flush()才行。
    但是如果在那个实体类上额外加上一个int或long的id,并且注解@GeneratedValue(我感觉是问题的关键),配置什么的都不用改就可以不手动调用flush(),而是事务提交时就自动发出insert语句并插入数据库了。
    forreal
        8
    forreal  
    OP
       2014-11-08 19:47:37 +08:00
    @forreal
    @qping
    没有错误日志(控制台上什么都没有)
    qping
        9
    qping  
       2014-11-08 20:03:51 +08:00
    你的代码呢
    forreal
        10
    forreal  
    OP
       2014-11-09 23:13:26 +08:00
    @qping

    model层:
    @Entity
    public class Node {

    private String name;

    @Id
    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }
    }

    dao层:
    baseDaoImpl.java:

    public class BaseDaoImpl {
    private SessionFactory sessionFactory;

    public SessionFactory getSessionFactory() {
    return sessionFactory;
    }

    @Resource(name = "sessionFactory")
    public void setSessionFactory(SessionFactory sessionFactory) {
    this.sessionFactory = sessionFactory;
    }
    public Session getCurrentSession(){
    return sessionFactory.getCurrentSession();
    }
    }

    NodeDaoImpl.java:

    @Repository
    public class NodeDaoImpl extends BaseDaoImpl implements NodeDao {

    @Override
    public Serializable save(Node node){
    Session session = getCurrentSession();
    session.setFlushMode(FlushMode.COMMIT);
    Serializable id = session.save(node);
    //session.flush();

    return id;
    }
    }

    service层:

    @Service
    public class NodeServiceImpl implements NodeService {
    @Override
    public Node add(Node node) {
    int id = (Integer)nodeDao.save(node);
    return node;

    }
    @Resource
    public void setNodeDao(NodeDao nodeDao) {
    this.nodeDao = nodeDao;
    }
    private NodeDao nodeDao;
    }

    controller层(spring mvc):

    @Controller
    @RequestMapping("/admin")
    public class AdminController {
    @RequestMapping
    public String index(){
    return "admin/admin";
    }

    @RequestMapping(value = "/node")
    public String addNode(@RequestParam("name")String nodename,ModelMap model){
    Node node = new Node();
    node.setName(nodename);
    nodeService.add(node);
    model.addAttribute("msg","添加成功");
    return "admin/admin";

    }

    @Resource
    public void setNodeService(NodeService nodeService) {
    this.nodeService = nodeService;
    }

    private NodeService nodeService;
    }

    spring-hibernate.xml配置文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 数据库连接配置 -->
    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${driveClassName}" />
    <property name="url" value="${jdbc_url}" />
    <property name="username" value="${jdbc_name}" />
    <property name="password" value="${jdbc_password}" />

    <property name="initialSize" value="5" />
    <property name="maxConnLifetimeMillis" value="60000" />
    <property name="maxTotal" value="20" />
    <property name="maxIdle" value="5" />
    </bean>

    <!-- Hibernate属性配置 -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="hibernateProperties">
    <props>
    <prop key="hibernate.hbm2ddl.auto">update</prop>
    <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
    <prop key="hibernate.show_sql">true</prop>
    <prop key="hibernate.format_sql">true</prop>
    </props>
    </property>
    <property name="packagesToScan">
    <list>
    <value>model</value>
    </list>
    </property>
    </bean>


    <!-- 事务配置 -->
    <!-- 需要引入tx的命名空间 -->
    <!-- 这是事务通知操作,使用的事务管理器引用自 transactionManager -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <tx:advice id="txAdvice" transaction-manager="transactionManager">
    <!-- 指定哪些方法需要加入事务,这里懒惰一下全部加入,可以使用通配符来只加入需要的方法 -->
    <tx:attributes>
    <tx:method name="save*" propagation="REQUIRED" />
    <tx:method name="add*" propagation="REQUIRED" />
    <tx:method name="edit*" propagation="REQUIRED" />
    <tx:method name="delete*" propagation="REQUIRED" />
    <tx:method name="get*" propagation="REQUIRED" read-only="true"/>
    <tx:method name="is*" propagation="REQUIRED" read-only="true"/>
    <tx:method name="follow*" propagation="REQUIRED" />
    <!--<tx:method name="*" propagation="REQUIRED" />-->
    </tx:attributes>
    </tx:advice>
    <!-- 需要引入aop的命名空间 -->
    <aop:config proxy-target-class="true">
    <!-- 切入点指明了在执行Service的所有方法时产生事务拦截操作 -->
    <aop:pointcut id="transactionPointcut" expression="execution(* service.Impl.*.*(..))" />
    <!-- 定义了将采用何种拦截操作,这里引用到 txAdvice -->
    <aop:advisor pointcut-ref="transactionPointcut" advice-ref="txAdvice" />
    </aop:config>
    </beans>
    qping
        11
    qping  
       2014-11-10 09:03:05 +08:00
    没看出哪有问题

    <tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
    <tx:method name="*" rollback-for="Exception"/>
    </tx:attributes>
    </tx:advice>

    改成这样试试
    qping
        12
    qping  
       2014-11-10 09:06:38 +08:00   ❤️ 1
    或者在service类上加 @Transactional 标签

    @Service
    @Transactional
    public class NodeServiceImpl implements NodeService {
    @Override
    public Node add(Node node) {
    int id = (Integer)nodeDao.save(node);
    return node;

    }
    forreal
        13
    forreal  
    OP
       2014-11-10 13:20:26 +08:00
    @qping

    xml加rollback-for="Exception" 和利用@Transactional都分别试过了,还是不行。
    还是需要显式调用flush()或者给实体加一个额外的id数字字段并且@GeneratedValue才可以插入数据库
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1134 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 18:38 · PVG 02:38 · LAX 10:38 · JFK 13:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.