Hibernate使用的一些细节注意事项

最近的一个项目,使用的是一个古老的开发脚手架平台JEECG,是的,从官网上可以看出这个脚手架是2013年的,现在他们官网主推的是JEECG BOOT,不过现在接手的这个项目是JEECG,项目中用到的持久层框架是Hibernate。由于基本上没用过Hibernate,所以在项目中踩了很多坑,出现问题,在网上找解决方案也非常少,针对最近遇到的一些问题,做个总结:

1,创建session的两种方式的不同

使用SessionFactory创建session的两种方式:使用openSession()这个方法或者getCurrentSession()方法,创建session,但是这两种是有很大差别的

使用openSession()创建的session是需要每次手工关闭session的,即调用session.close()方法。所以在使用@transactional注解的service层,调用dao层增删改查的时候,事务通常会不起作用,因为调用的时候,session已经关闭了,事务不能正常激活,

像这样的写法就不行的,例如下service层中,调用这个save方法,一调用session就关闭了,事务无法参与进去:

Repository("hotelPreOrderDao")
public class HotelPreOrderDaoImpl implements HotelPreOrderDao{

    private TmcHotelPreOrder tmcHotelPreOrder=new TmcHotelPreOrder();
    @Autowired
    SessionFactory sessionFactory;
    @Override
    public void save(TmcHotelPreOrder tmcHotelPreOrder) {
        Session session = sessionFactory.openSession();
        session.save(tmcHotelPreOrder);
        session.close();

    }

    @Override
    public void update(TmcHotelPreOrder tmcHotelPreOrder) {
        Session session = sessionFactory.openSession();
        session.update(tmcHotelPreOrder);
        session.close();

    }

}

 

这样写的话,在service层的方法中虽然加了@transactional注解,在service层的方法中调用HotelPreOrderDao.save()方法,事务是不起效的,会报错;

所以可以使用另外一种获取session的方法,这种可以在执行完事务后,自动关闭session,如下:

@Repository("hotelPreOrderDao")
public class HotelPreOrderDaoImpl implements HotelPreOrderDao{

    private TmcHotelPreOrder tmcHotelPreOrder=new TmcHotelPreOrder();
    @Autowired
    SessionFactory sessionFactory;
    @Override
    public void save(TmcHotelPreOrder tmcHotelPreOrder) {
        Session session = sessionFactory.getCurrentSession();
        session.save(tmcHotelPreOrder);
    }

    @Override
    public void update(TmcHotelPreOrder tmcHotelPreOrder) {
        Session session = sessionFactory.getCurrentSession();
        session.update(tmcHotelPreOrder);

    }

    @Override
    public void delete(Serializable id) {
        Session session = sessionFactory.getCurrentSession();
        session.delete(this.findById(id));

    }

    @Override
    public TmcHotelPreOrder findById(Serializable id) {
        Session session = sessionFactory.getCurrentSession();
        return (TmcHotelPreOrder)session.get(tmcHotelPreOrder.getClass(),id);

    }

    /**
     * 通过hql查询
     * @param hql
     * @param paranms 条件参数值
     * @return 查询结果,多条数据
     */
    @Override
    public List<TmcHotelPreOrder> findByHQL(String hql, Object... paranms) {
        Session session = sessionFactory.getCurrentSession();
        Query query = session.createQuery(hql);
        for (int i=0;paranms!=null&&i<paranms.length;i++){
            query.setParameter(i,paranms);
        }
        return query.list();
    }
}
 

sessionFactory是在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:context="http://www.springframework.org/schema/context" 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/context
       http://www.springframework.org/schema/context/spring-context.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">

    <context:component-scan base-package="com.gbiac.hotelier.*"/>
    <context:property-placeholder location="classpath:dbconfig.properties"/>

    <!--配置c3p0-->
    <!--配置c3p0-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${jdbc.username.jeecg}"></property>
        <property name="password" value="${jdbc.password.jeecg}"></property>
        <property name="driverClass" value="${jdbc.driver}"></property>
        <property name="jdbcUrl" value="${jdbc.url.jeecg}"></property>
        <property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
        <property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
    </bean>
    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:hibernate.cfg.xml"/>
        <property name="packagesToScan">
            <list>
                <value>com.gbiac.hotelier.*</value>
            </list>
        </property>
    </bean>

    <bean name="transactionManager"
          class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--配置注解驱动,使可以使用注解来管理事务-->
    <tx:annotation-driven transaction-manager="transactionManager"/>

    </beans>

同时还有一个hibernate的配置项需要注释掉,或者不配置:hibernate.cfg.xml文件

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!--配置基本属性-->

     
        <!--hibernate方言-->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
        <!-- 在控制台显示执行的sql语句 -->
        <property name="hibernate.show_sql">true</property>
        <!-- 格式化sql语句,更易读 -->
        <property name="hibernate.format_sql">true</property>

        <!--生成数据表策略-->
        <!--<property name="hibernate.hbm2ddl.auto">update</property>-->

        <!-- 启用二级缓存 -->
        <!--<property name="cache.use_second_level_cache">true</property>-->
        <!--&lt;!&ndash; 设置二级缓存的实现类,即指定使用的插件 &ndash;&gt;-->
        <!--<property name="cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>-->
        <!--&lt;!&ndash; 启用查询缓存 &ndash;&gt;-->
        <!--<property name="cache.use_query_cache">true</property>-->

        <!--把session绑定到本地线程-->
        <!--<property name="hibernate.current_session_context_class">thread</property>-->
    </session-factory>
</hibernate-configuration>

将那个绑定本地线程的配置注释掉,或者删除这个配置项

这样就可以正常用@transactional注解来管理事务,同时session也不用手动去关闭了,getCurrentSession()会在事务提交后,自动关闭session。

service层加@transactional注解来管理事务

2,HQL写法与hibernate支持的原生sql写法的区别

今天本来是要用hql语句写更新语句,结果在建立执行语句时用错了方法

@Override
    public Integer updateByHQL(String fcOrderCode,Integer orderStatus,String orderStatusMessage) {
        Session session=sessionFactory.getCurrentSession();
//        原生sql方式更新
//        String updateSql="update tmc_hotel_order set order_status= :order_status,order_status_message= :order_status_message where fc_order_code= :fc_order_code ";
//        int rowNum = session.createSQLQuery(updateSql).setInteger("order_status", orderStatus).setString("order_status_message", orderStatusMessage)
//                .setString("fc_order_code", fcOrderCode).executeUpdate();
//        HQL方式更新
        String hql="update TmcHotelOrder set orderStatus= :order_status,orderStatusMessage= :order_status_message,modifiedTime= :modified_time where fcOrderCode= :fc_order_code ";
//        保留日期和时间需要使用setTimeStamp方法,setDate截断time,SetTime会截断date
        int rowNum = session.createQuery(hql).setInteger("order_status", orderStatus).setString("order_status_message", orderStatusMessage)
                .setString("fc_order_code", fcOrderCode).setTimestamp("modified_time",new Date()).
                        executeUpdate();
        return rowNum;

    }

 我最初用的hql语句写的更新语句,表名和字段用的都是实体类的类名和属性名,因为在实体类中已经用JPA注解映射了实体类和数据表的对应关系,hql语句写的是正确的,但是比较坑的地方是下边这样:

 String hql="update TmcHotelOrder set orderStatus= :order_status,orderStatusMessage= :order_status_message,modifiedTime= :modified_time where fcOrderCode= :fc_order_code ";

int rowNum = session.createSQLQuery(updateSql).setInteger("order_status", orderStatus).setString("order_status_message", orderStatusMessage)
               .setString("fc_order_code", fcOrderCode).executeUpdate();

是的,我用错方法了,我用成了session.createSQLQuery()这个方法,但是这样用的话,是不对的,hibernate的update语句就变成了update TmcHotelOrder ...,但是根本不存在TmcHotelOrder 这个数据表,运行项目,也会报错,说TmcHotelOrder table not  exist;因为session.createSQLQuery()这个方法是执行原生SQL语句的,要使用这个方法,表名和字段名需要是真实的表名和字段名,而不应该是映射的实体类名和属性名。

所以后边改过来了,HQL的增删改查,需要使用session.createQuery(hql)这个方法。这样hibernate会自动根据映射关系,在执行update语句时,会自动更改成表名为tmc_hotel_order,属性名也会自动映射成真正的字段名,就和原生sql的增删改查是一样的啦。

实体类时这样的:

package com.gbiac.hotelier.entity;

import org.springframework.format.annotation.DateTimeFormat;

import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;

/**
 * 酒店预订表
 */
@Entity
@Table(name = "tmc_hotel_order")
public class TmcHotelOrder implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 主键id
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private Integer id;

    /**
     * 酒店id
     */
    @Column(name = "hotel_id")
    private Integer hotelId;

    /**
     * 房型id
     */
    @Column(name = "room_id")
    private Integer roomId;

    /**
     * 价格计划id
     */
    @Column(name = "rate_plan_id")
    private Integer ratePlanId;

    /**
     * 入住日期
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @Column(name = "check_in_date")
    private Date checkInDate;

    /**
     * 离店日期
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @Column(name = "check_out_date")
    private Date checkOutDate;

    /**
     * 预订间数
     */
    @Column(name = "room_num")
    private Integer roomNum;

    /**
     * 房间状态 1:有房 2:待查 3:满房
     */
    @Column(name = "room_status")
    private Integer roomStatus;

    /**
     * 床型
     */
    @Column(name = "bed_type")
    private String bedType;

    /**
     * 总金额
     */
    @Column(name = "total_amount")
    private Double totalAmount;

    /**
     * 合作商订单号
     */
    @Column(name = "co_order_code")
    private String coOrderCode;

    /**
     * 泰坦云订单号
     */
    @Column(name = "fc_order_code")
    private String fcOrderCode;

    /**
     * 预订结果 1-预订成功  2-预订失败 
     */
    @Column(name = "result", nullable = false)
    private Integer result;

    /**
     * 预订失败的原因
     */
    @Column(name = "message")
    private String message;

    /**
     * 订单状态 1:新建  2:处理中 3:已确认 4:已取消
     */
    @Column(name = "order_status", nullable = false)
    private Integer orderStatus;
    @Column(name = "order_status_message")
    private String orderStatusMessage;

    public String getOrderStatusMessage() {
        return orderStatusMessage;
    }

    public void setOrderStatusMessage(String orderStatusMessage) {
        this.orderStatusMessage = orderStatusMessage;
    }

    /**
     * 订单联系人
     */
    @Column(name = "link_man", nullable = false)
    private String linkMan;

    /**
     * 联系人电话
     */
    @Column(name = "link_phone", nullable = false)
    private String linkPhone;

    /**
     * 邮箱
     */
    @Column(name = "email")
    private String email;

    /**
     * 到店时间(格式HH:mm)
     */
    @Column(name = "arrive_time", nullable = false)
    private String arriveTime;

    /**
     * 最晚到店时间(格式HH:mm)
     */
    @Column(name = "latest_arrive_time", nullable = false)
    private String latestArriveTime;

    /**
     * 供应商编码
     */
    @Column(name = "supply_code", nullable = false)
    private String supplyCode;

    /**
     * 客户特殊要求
     */
    @Column(name = "special_demand")
    private String specialDemand;

    /**
     * 订单创建时间
     */
    @Column(name = "create_time")
    private Date createTime;

    /**
     * 订单修改时间
     */
    @Column(name = "modified_time")
    private Date modifiedTime;

    /**
     * 操作者
     */
    @Column(name = "operator")
    private String operator;

    /**
     * 备注字段
     */
    @Column(name = "remark")
    private String remark;

    /**
     * 主键id
     */
    public Integer getId() {
        return id;
    }

    /**
     * 主键id
     */
    public void setId(Integer id) {
        this.id = id;
    }

    /**
     * 酒店id
     */
    public Integer getHotelId() {
        return hotelId;
    }

    /**
     * 酒店id
     */
    public void setHotelId(Integer hotelId) {
        this.hotelId = hotelId;
    }

    /**
     * 房型id
     */
    public Integer getRoomId() {
        return roomId;
    }

    /**
     * 房型id
     */
    public void setRoomId(Integer roomId) {
        this.roomId = roomId;
    }

    /**
     * 价格计划id
     */
    public Integer getRatePlanId() {
        return ratePlanId;
    }

    /**
     * 价格计划id
     */
    public void setRatePlanId(Integer ratePlanId) {
        this.ratePlanId = ratePlanId;
    }

    /**
     * 入住日期
     */
    public Date getCheckInDate() {
        return checkInDate;
    }

    /**
     * 入住日期
     */
    public void setCheckInDate(Date checkInDate) {
        this.checkInDate = checkInDate;
    }

    /**
     * 离店日期
     */
    public Date getCheckOutDate() {
        return checkOutDate;
    }

    /**
     * 离店日期
     */
    public void setCheckOutDate(Date checkOutDate) {
        this.checkOutDate = checkOutDate;
    }

    /**
     * 预订间数
     */
    public Integer getRoomNum() {
        return roomNum;
    }

    /**
     * 预订间数
     */
    public void setRoomNum(Integer roomNum) {
        this.roomNum = roomNum;
    }

    /**
     * 房间状态 1:有房 2:待查 3:满房
     */
    public Integer getRoomStatus() {
        return roomStatus;
    }

    /**
     * 房间状态 1:有房 2:待查 3:满房
     */
    public void setRoomStatus(Integer roomStatus) {
        this.roomStatus = roomStatus;
    }

    /**
     * 床型
     */
    public String getBedType() {
        return bedType;
    }

    /**
     * 床型
     */
    public void setBedType(String bedType) {
        this.bedType = bedType;
    }

    /**
     * 总金额
     */
    public Double getTotalAmount() {
        return totalAmount;
    }

    /**
     * 总金额
     */
    public void setTotalAmount(Double totalAmount) {
        this.totalAmount = totalAmount;
    }

    /**
     * 合作商订单号
     */
    public String getCoOrderCode() {
        return coOrderCode;
    }

    /**
     * 合作商订单号
     */
    public void setCoOrderCode(String coOrderCode) {
        this.coOrderCode = coOrderCode;
    }

    /**
     * 泰坦云订单号
     */
    public String getFcOrderCode() {
        return fcOrderCode;
    }

    /**
     * 泰坦云订单号
     */
    public void setFcOrderCode(String fcOrderCode) {
        this.fcOrderCode = fcOrderCode;
    }

    /**
     * 预订结果 1-预订成功  2-预订失败 
     */
    public Integer getResult() {
        return result;
    }

    /**
     * 预订结果 1-预订成功  2-预订失败 
     */
    public void setResult(Integer result) {
        this.result = result;
    }

    /**
     * 预订失败的原因
     */
    public String getMessage() {
        return message;
    }

    /**
     * 预订失败的原因
     */
    public void setMessage(String message) {
        this.message = message;
    }

    /**
     * 订单状态 1:新建  2:处理中 3:已确认 4:已取消
     */
    public Integer getOrderStatus() {
        return orderStatus;
    }

    /**
     * 订单状态 1:新建  2:处理中 3:已确认 4:已取消
     */
    public void setOrderStatus(Integer orderStatus) {
        this.orderStatus = orderStatus;
    }

    /**
     * 订单联系人
     */
    public String getLinkMan() {
        return linkMan;
    }

    /**
     * 订单联系人
     */
    public void setLinkMan(String linkMan) {
        this.linkMan = linkMan;
    }

    /**
     * 联系人电话
     */
    public String getLinkPhone() {
        return linkPhone;
    }

    /**
     * 联系人电话
     */
    public void setLinkPhone(String linkPhone) {
        this.linkPhone = linkPhone;
    }

    /**
     * 邮箱
     */
    public String getEmail() {
        return email;
    }

    /**
     * 邮箱
     */
    public void setEmail(String email) {
        this.email = email;
    }

    /**
     * 到店时间(格式HH:mm)
     */
    public String getArriveTime() {
        return arriveTime;
    }

    /**
     * 到店时间(格式HH:mm)
     */
    public void setArriveTime(String arriveTime) {
        this.arriveTime = arriveTime;
    }

    /**
     * 最晚到店时间(格式HH:mm)
     */
    public String getLatestArriveTime() {
        return latestArriveTime;
    }

    /**
     * 最晚到店时间(格式HH:mm)
     */
    public void setLatestArriveTime(String latestArriveTime) {
        this.latestArriveTime = latestArriveTime;
    }

    /**
     * 供应商编码
     */
    public String getSupplyCode() {
        return supplyCode;
    }

    /**
     * 供应商编码
     */
    public void setSupplyCode(String supplyCode) {
        this.supplyCode = supplyCode;
    }

    /**
     * 客户特殊要求
     */
    public String getSpecialDemand() {
        return specialDemand;
    }

    /**
     * 客户特殊要求
     */
    public void setSpecialDemand(String specialDemand) {
        this.specialDemand = specialDemand;
    }

    /**
     * 订单创建时间
     */
    public Date getCreateTime() {
        return createTime;
    }

    /**
     * 订单创建时间
     */
    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    /**
     * 订单修改时间
     */
    public Date getModifiedTime() {
        return modifiedTime;
    }

    /**
     * 订单修改时间
     */
    public void setModifiedTime(Date modifiedTime) {
        this.modifiedTime = modifiedTime;
    }

    /**
     * 操作者
     */
    public String getOperator() {
        return operator;
    }

    /**
     * 操作者
     */
    public void setOperator(String operator) {
        this.operator = operator;
    }

    /**
     * 备注字段
     */
    public String getRemark() {
        return remark;
    }

    /**
     * 备注字段
     */
    public void setRemark(String remark) {
        this.remark = remark;
    }

    @Override
    public String toString() {
        return "TmcHotelOrder{" +
                "id=" + id +
                ", hotelId=" + hotelId +
                ", roomId=" + roomId +
                ", ratePlanId=" + ratePlanId +
                ", checkInDate=" + checkInDate +
                ", checkOutDate=" + checkOutDate +
                ", roomNum=" + roomNum +
                ", roomStatus=" + roomStatus +
                ", bedType='" + bedType + '\'' +
                ", totalAmount=" + totalAmount +
                ", coOrderCode='" + coOrderCode + '\'' +
                ", fcOrderCode='" + fcOrderCode + '\'' +
                ", result=" + result +
                ", message='" + message + '\'' +
                ", orderStatus=" + orderStatus +
                ", orderStatusMessage='" + orderStatusMessage + '\'' +
                ", linkMan='" + linkMan + '\'' +
                ", linkPhone='" + linkPhone + '\'' +
                ", email='" + email + '\'' +
                ", arriveTime='" + arriveTime + '\'' +
                ", latestArriveTime='" + latestArriveTime + '\'' +
                ", supplyCode='" + supplyCode + '\'' +
                ", specialDemand='" + specialDemand + '\'' +
                ", createTime=" + createTime +
                ", modifiedTime=" + modifiedTime +
                ", operator='" + operator + '\'' +
                ", remark='" + remark + '\'' +
                '}';
    }
}

表字段是这样的:

控制台中,使用hql方式执行的更新,语句输出在控制台中是这样的:

 先暂时更新到这里。现在不早了,这个月先总结这些吧,最近很忙,写博客的时间很少!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值