本篇讲Spring4.3.2集成Hibernate5.2.5(目前最新版本),先说下环境配置
一、环境配置
1)jdk1.8.0_101,Hibernate5.2.5要求jdk8
2)tomcat8.0.0,由于8以下版本和jdk8不兼容,所以采取tomcat8
3)mysql5.1.38
4)需要的库
//hibernate
compile group: 'org.springframework', name: 'spring-orm', version: "$springVersion"
compile group: 'org.hibernate', name: 'hibernate-core', version: '5.2.5.Final'
//mysql
compile "mysql:mysql-connector-java:5.1.38"
//c3p0
//compile "c3p0:c3p0:0.9.1.2"
compile group: 'org.hibernate', name: 'hibernate-c3p0', version: '5.2.5.Final'
//aspectj
compile group: 'org.aspectj', name: 'aspectjweaver', version: '1.8.9'
二、数据源和Hibernate5配置
1)数据源配置applicationContext-dao.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"
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">
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置数据源 -->
<!-- 配置C3P0连接池: -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!--每5小时检查所有连接池中的空闲连接。防止mysql wait_timeout(默认的为8小时) -->
<property name="idleConnectionTestPeriod" value="${jdbc.c3p0.idleConnectionTestPeriod}"/>
</bean>
<!-- 配置hibernate -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan">
<list>
<!-- 可以加多个包 -->
<value>com.mango.jtt.po</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
</props>
</property>
</bean>
<!--<start id="bean_exception_translation_post_processor" />-->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<!--<end id="bean_exception_translation_post_processor" />-->
<context:component-scan base-package="com.mango.jtt"></context:component-scan>
</beans>
其中数据源的配置是采用的c3p0资源池,c3p0的基本配置可参考:C3P0连接池+MySQL的配置以及wait_timeout问题的解决(Hibernate官方文档中说,当使用c3p0资源池时,应用程序必须将 hibernate-c3p0 的 jar 包(还有它的辅助包)放到 classpath 中。),jdbc.properties文件如下:<context:property-placeholder/>标签可参考Spring类PropertyPlaceholderConfigurer的作用
#-----------------------------------------------------
# 数据库配置
#-----------------------------------------------------
#服务器地址
host=127.0.0.1
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://${host}:3306/hhl
jdbc.username=root
jdbc.password=123456
#-----------------------------------------------------
# 适用于c3p0的配置
#-----------------------------------------------------
#-----------------------------------------------------
# c3p0反空闲设置,防止8小时连接失效问题28800
#-----------------------------------------------------
#idleConnectionTestPeriod要小于MySQL的wait_timeout 默认为8小时
jdbc.c3p0.testConnectionOnCheckout=false
jdbc.c3p0.testConnectionOnCheckin=true
jdbc.c3p0.idleConnectionTestPeriod=18000
#-----------------------------------------------------
# c3p0连接池配置
#-----------------------------------------------------
#initialPoolSize, minPoolSize, maxPoolSize define the number of Connections that will be pooled.
#Please ensure that minPoolSize <= maxPoolSize.
#Unreasonable values of initialPoolSize will be ignored, and minPoolSize will be used instead.
jdbc.c3p0.initialPoolSize=10
jdbc.c3p0.minPoolSize=10
jdbc.c3p0.maxPoolSize=100
#maxIdleTime defines how many seconds a Connection should be permitted to go unused before being culled from the pool.
jdbc.c3p0.maxIdleTime=3600
#-----------------------------------------------------
# hibernate配置
#-----------------------------------------------------
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect #方言类型
hibernate.show_sql=true
hibernate.format_sql=true
hibernate.hbm2ddl.auto=update #自动建表功能
2)hibernate5配置
sessionFactory用的是LocalSessionFactoryBean,4以后就只有这一种结合了两者,3以前包括AnnotationSessionFactoryBean
org.springframework.orm.hibernate5.LocalSessionFactoryBean
并且使用的是使用packagesToScan属性告诉Spring扫描一个或多个包以查找域类,这些类通过注解的方式表明要使用Hibernate进行持久化,这些类可以使用的注解包括JPA的@Entity或@MappedSuperclass以及Hibernate的@Entity。
三、pojo的定义
其中用的注解的方式进行的映射,@Id是必须有的,@Column非必须,如果字段名和列名相同的话就不需要加
Product.java
package com.mango.jtt.po;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* @author HHL
*
* @date 2016年9月12日
*
* 商品类
*/
@Entity
@Table(name = "product")
public class Product extends BaseBean {
/**
*
*/
private static final long serialVersionUID = 3844317879498218112L;
/**
* 商品id
*/
@Id
private String productId;
/**
* 商品名称
*/
private String productName;
/**
* 商品单价
*/
private double unitPrice;
/**
* 库存
*/
private double quantity;
/**
* 单位
*/
private String unit;
/**
* 商品图片地址
*/
private String picture;
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
public double getQuantity() {
return quantity;
}
public void setQuantity(double quantity) {
this.quantity = quantity;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public double getUnitPrice() {
return unitPrice;
}
public void setUnitPrice(double unitPrice) {
this.unitPrice = unitPrice;
}
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit;
}
public String getPicture() {
return picture;
}
public void setPicture(String picture) {
this.picture = picture;
}
}
四、dao类
/**
*
*/
package com.mango.jtt.dao;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
/**
* @author HHL
*
* @date 2016年11月30日
*/
@Repository
public class MangoDaoImpl implements IMangoDao {
@Autowired
private SessionFactory sessionFactory;
private Session currentSession() {
return sessionFactory.getCurrentSession();
}
/* (non-Javadoc)
* @see com.mango.jtt.dao.MangoDao#list(java.lang.String)
*/
@Override
public List list(String querySql) {
Query<?> query = currentSession().createQuery(querySql);
return query.getResultList();
}
@Override
public Object get(Class clazz, String productId) {
return currentSession().get(clazz, productId);
}
@Override
public void saveBean(Object object) {
currentSession().save(object);
}
@Override
public void updateBean(Object object) {
currentSession().update(object);
}
}
使用@Repository注解,这会为我们做两件事情。首先,@Repository是Spring的另一种构造性注解,它能够像其他注解一样被Spring的组件扫描所扫描到。这样就不必明确声明HibernateSpitterRepositorybean了,只要这个Repository类在组件扫描所涵盖的包中即可。除了帮助减少显式配置以外,@Repository还有另外一个用处。让我们回想一下模板类,它有一项任务就是捕获平台相关的异常,然后使用Spring统一非检查型异常的形式重新抛出。如果我们使用Hibernate上下文Session而不是Hibernate模板的话,那异常转换会怎么处理呢?为了给不使用模板的Hibernate Repository添加异常转换功能,我们只需在Spring应用上下文中添加一个PersistenceExceptionTranslationPostProcessorbean,PersistenceExceptionTranslationPostProcessor是一个bean后置处理器(bean post-processor),它会在所有拥有@Repository注解的类上添加一个通知器(advisor),这样就会捕获任何平台相关的异常并以Spring非检查型数据访问异常的形式重新抛出。
使用@Autowired注解(基于类型进行装配)将SessionFactory装配进来,使用sessionFactory.getCurrentSession()来获取当前事务的session,sessionFactory.getCurrentSession()的使用需要配置spring事务,否则会抛Could not obtain transaction-synchronized Session for current thread异常,applicationContext-transaction.xml,异常和事务的配置会在后面的文章中详解
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd ">
<bean id="transactionManager" class="org.springframework.orm.hibernate5.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="delete*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="list*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- aop -->
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.mango.jtt.service.*.*(..))"/>
</aop:config>
<!-- 注解管理事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
五、Service类
/**
*
*/
package com.mango.jtt.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.mango.jtt.dao.IMangoDao;
import com.mango.jtt.po.Product;
/**
* @author HHL
*
* @date 2016年11月30日
*/
@Service
public class ProductServiceImpl implements IProductService {
@Autowired
private IMangoDao dao;
/* (non-Javadoc)
* @see com.mango.jtt.service.ProductService#getProductList()
*/
@Override
public List<Product> getProductList() {
String sql = "from Product";
return dao.list(sql);
}
@Override
public Product getProductById(String productId) {
return (Product) dao.get(Product.class, productId);
}
}
/**
*
*/
package com.mango.jtt.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.mango.jtt.dao.IMangoDao;
import com.mango.jtt.po.Order;
/**
* @author HHL
*
* @date 2016年12月1日
*/
@Service
public class OrderService implements IOrderService {
@Autowired
private IMangoDao dao;
/* (non-Javadoc)
* @see com.mango.jtt.service.IOrderService#addOrder(com.mango.jtt.po.Order)
*/
@Override
public void saveOrder(Order order) {
dao.saveBean(order);
}
/* (non-Javadoc)
* @see com.mango.jtt.service.IOrderService#getOrderById(java.lang.String)
*/
@Override
public Order getOrderById(String orderId) {
return (Order) dao.get(Order.class, orderId);
}
/* (non-Javadoc)
* @see com.mango.jtt.service.IOrderService#updateOrderPay(com.mango.jtt.po.Order)
*/
@Override
public void updateOrder(Order order) {
dao.updateBean(order);
}
}
利用@Autowired注解就可以使用dao类了
六、springMVC的使用
/**
*
*/
package com.mango.jtt.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import com.mango.jtt.po.Product;
import com.mango.jtt.service.IProductService;
/**
* @author HHL
*
* @date 2016年11月30日
*/
@Controller
public class ProductController {
@Autowired
private IProductService productService;
@RequestMapping("/product/{productId}")
public String getProductById(Model model, @PathVariable String productId) {
Product product = productService.getProductById(productId);
model.addAttribute("product", product);
return "product_detail";
}
}
/**
*
*/
package com.mango.jtt.controller;
import java.util.Date;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import com.mango.jtt.po.Order;
import com.mango.jtt.service.IOrderService;
import com.mango.jtt.util.DateUtil;
/**
* 订单控制类
*
* @author HHL
*
* @date 2016年12月1日
*/
@Controller
public class OrderController {
@Autowired
private IOrderService orderService;
/**
* @param order
* @param session
* @param model
* @return 保存订单
*/
@RequestMapping("order/submit")
public String orderSubmit(Order order, HttpSession session, Model model) {
order.setTotalPrice(order.getUnitPrice() * order.getNumber());
order.setOrderId(DateUtil.getDateFormat1(new Date()));
order.setCreateTime(DateUtil.getDateFormat2(new Date()));
// Customer user = (Customer) session.getAttribute("user");
orderService.saveOrder(order);
// 改用spring aspect
// LogUtil.testLogError("addOrder 返回值:" + res, null);
model.addAttribute("orderId", order.getOrderId());
// 防止重复提交
return "redirect:/order/{orderId}";
}
/**
* @param orderId
* @param model
* @return 订单信息
*/
@RequestMapping("order/{orderId}")
public String orderSave(@PathVariable String orderId, Model model) {
Order order = orderService.getOrderById(orderId);
model.addAttribute("order", order);
return "order_submit";
}
/**
* @param orderId
* @param model
* @return 订单支付信息
*/
@RequestMapping("pay/{orderId}")
public String orderPayInfo(@PathVariable String orderId, Model model) {
Order order = orderService.getOrderById(orderId);
model.addAttribute("order", order);
return "order_pay";
}
/**
* @param orderId
* @param model
* @return 订单支付
*/
@RequestMapping("order/{orderId}/pay")
public String orderPay(@PathVariable String orderId, Model model) {
Order order = orderService.getOrderById(orderId);
order.setStatus("1");
order.setPayTime(DateUtil.getDateFormat2(new Date()));
orderService.updateOrder(order);
return "redirect:/pay/{orderId}";
}
}
七、springMVC4+Spring4+Hibernate5+MySQL5的完整代码
SpringMVC4+Spring4+Hibernate5+MySQL5 或 https://github.com/honghailiang/SpringMango