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

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

  •  
  •   forreal Nov 7, 2014 8601 views
    This topic created in 4204 days ago, the information mentioned may be changed or developed.
    我之前写了一个entity类,@Id注解在String类型的name字段上。(因为就这一个字段,另外加一个id字段浪费)。
    然后当我session.save()时,不生成insert语句,也不插入数据库。除非我session.flush()一下才插入数据库。
    而当我把entity类增加一个Long类型的id字段并且设置自动增长时,再session.save()时,就既生成insert语句又插入字段。
    请问这是为什么呢?
    13 replies    2014-11-10 13:20:26 +08:00
    welsmann
        1
    welsmann  
       Nov 7, 2014   1
    根据需要加入@GeneratedValue注解
    qping
        2
    qping  
       Nov 7, 2014   1
    下面是百度搜的,印象中是这样的。
    "session在什么情况下执行flush:默认在事务提交时;显示的调用flush;在执行查询前,如:iterate.
    调用save后,只是将对象纳入到了session的管理,不会发出insert语句,如没有主键会根据主键生成策略生成主键,把脱管或瞬态对象变为持久态对象."

    http://zhidao.baidu.com/link?url=p8o00ykbezRThHvydBXl3RvUZFO1cvOTB-XcD3m5I2K1idgOcSdTAP2GAC-xEaJOCe01G5S7mOSfMpzzvH5m-K
    shuson
        3/span>
    shuson  
       Nov 8, 2014   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
       Nov 8, 2014
    @welsmann 主键我想自己指定,不想自动生成。但是我试了如果实体的主键是Long类型却不加@GeneratedValue 也会save()时不插入数据库。

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

    @shuson 意思是先用自动生成主键,然后再@PrePersist注解的方法 改对象的主键吗?
    qping
        5
    qping  
       Nov 8, 2014
    有其他语句吗 比如update语句,没有错误日志,相关配置,只能等高手过来帮你猜了 - -
    qping
        6
    qping  
       Nov 8, 2014
    我始终不认为你错的地方在于注解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
       Nov 8, 2014
    @qping 没有错误日志(控制台上sql语句,错误日志什么都没有),
    配置都是照https://github.com/ZhibingXie/SpringMVC-Spring-Hibernate来配的。
    就是有一个实体类,id用的是名字(String类型),而且没有注解@GeneratedValue,然后事务提交不发出insert语句也不存入数据库。必须手动调用flush()才行。
    但是如果在那个实体类上额外加上一个int或long的id,并且注解@GeneratedValue(我感觉是问题的关键),配置什么的都不用改就可以不手动调用flush(),而是事务提交时就自动发出insert语句并插入数据库了。
    forreal
        8
    forreal  
    OP
       Nov 8, 2014
    @forreal
    @qping
    没有错误日志(控制台上什么都没有)
    forreal
        10
    forreal  
    OP
       Nov 9, 2014
    @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  
       Nov 10, 2014
    没看出哪有问题

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

    改成这样试试
    qping
        12
    qping  
       Nov 10, 2014   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
       Nov 10, 2014
    @qping

    xml加rollback-for="Exception" 和利用@Transactional都分别试过了,还是不行。
    还是需要显式调用flush()或者给实体加一个额外的id数字字段并且@GeneratedValue才可以插入数据库
    About     Help     Advertise     Blog     API     FAQ     Solana     3178 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 36ms UTC 14:42 PVG 22:42 LAX 07:42 JFK 10:42
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86