Spring整合Hibernate实现JPA持久化
Spring整合Hibernate实现JPA持久化
本篇文章主要介绍Spring如何集成JPA的功能,并实现基本的CURD操作。JPA,全称为JavaPersistence API,诞生与EJB2实体Bean之上,是一种新的Java持久化标准,也是基于POJO的持久化机制,它的设计灵感来源于Hibernate和Java数据对象(JDO)。
l Maven管理软包依赖
l 配置实体管理器工厂
l 用JPA方式实现CURD
一、Maven管理软包依赖
这里采用Maven来集成和管理Spring、Hibernate及其它相关的软件包依赖,好处就不多说了。需要注意的是Spring和Hibernate的版本选择必须兼容,否则就会出现各种问题(笔者可是吃过亏的哦),具体各个版本的对应关系,请看下面的pom.xml配置:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.tomcat.version>8.0.0-RC5</project.tomcat.version>
<spring.version>4.3.0.RELEASE</spring.version>
<hibernate.version>5.2.2.Final</hibernate.version>
<mysql.connector.version>5.1.30</mysql.connector.version>
<junit.version>4.12</junit.version>
<javax.servlet-api.version>3.1.0</javax.servlet-api.version>
<javax.servlet.jsp.version>2.3.1</javax.servlet.jsp.version>
<slf4j.version>1.7.5</slf4j.version>
<jstl.version>1.2</jstl.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- Logger -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Servlet+JSP+jstl-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${javax.servlet-api.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>${javax.servlet.jsp.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
<!-- Hibernate -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- Mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.connector.version}</version>
</dependency>
<!-- apache commons -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>20030825.184428</version>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>20030825.183949</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>2.1</version>
</dependency>
</dependencies>
二、配置实体管理器工厂
我们知道,基于JPA的应用程序需要使用EntityManagerFactory的实现来获取EntityManager实例,目前JPA定义了两种类型的实体管理器,它们分别是:应用程序管理类型和容器管理类型。对于前者,程序需要负责打开和关闭实体管理器,并要在事务中对其进行控制,此种方式的实体管理器适合于非运行在Java EE容器中的独立应用程序;而后者,应用程序不需要与实体管理器工厂交互,而是交由容器与其进行交互,实体管理器可直接注入或JNDI来获取,此种类型的实体管理器适合于Java EE容器,所以这里介绍后者。
1、声明实体管理器工厂
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean emf =new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource());
emf.setJpaVendorAdapter(hibernateJpaVendorAdapter());
emf.setPackagesToScan("com.cwteam.orm.model"); // 替代persistences.xml,对该路径下的@Entity扫描初始化
Map<String,String> jpsMaps =new HashMap<String,String>(); // 实体管理器参数的配置
jpsMaps.put("hibernate.show_sql","true");
jpsMaps.put("hibernate.hbm2ddl.auto","update");
jpsMaps.put("hibernate.dialect","org.hibernate.dialect.MySQLDialect");
emf.setJpaPropertyMap(jpsMaps);
returnemf;
}
这里设置了数据源dataSource和指定了选用哪种类型实现的JPA,这里选用了HibernateJpaVendorAdapter适配器,并且使用setPackagesToScan来自动初始化扫描模型Entity实体类,替代了传统的persistences.xml类似的作用。
dataSource配置:
@Bean
public BasicDataSource dataSource() {
BasicDataSource dataSource =new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8");
dataSource.setUsername("root");
dataSource.setPassword(null);
dataSource.setDefaultAutoCommit(false);
returndataSource;
}
hibernateJpaVendorAdaptor配置:
@Bean
public JpaVendorAdapter hibernateJpaVendorAdapter(){
HibernateJpaVendorAdapter jpaVA =new HibernateJpaVendorAdapter();
jpaVA.setDatabasePlatform("org.hibernate.dialect.MySQLDialect"); // MySQL平台指定
returnjpaVA;
}
完整的Spring上下文配置如下:
@Configuration
@ComponentScan("com.cwteam.orm.*")
@EnableTransactionManagement // 开启事务及对注解@Transactional的支持
public class SpringConfig {
// 实体管理工厂配置
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean emf =new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource());
emf.setJpaVendorAdapter(hibernateJpaVendorAdapter());
emf.setPackagesToScan("com.cwteam.orm.model"); // 替代persistences.xml,对该路径下的@Entity扫描初始化
Map<String,String>jpsMaps =new HashMap<String,String>(); // 实体管理器参数的配置
jpsMaps.put("hibernate.show_sql","true");
jpsMaps.put("hibernate.hbm2ddl.auto","update");
jpsMaps.put("hibernate.dialect","org.hibernate.dialect.MySQLDialect");
emf.setJpaPropertyMap(jpsMaps);
returnemf;
}
// JPA的实体适配器
@Bean
public JpaVendorAdapter hibernateJpaVendorAdapter(){
HibernateJpaVendorAdapter jpaVA =new HibernateJpaVendorAdapter();
jpaVA.setDatabasePlatform("org.hibernate.dialect.MySQLDialect"); // MySQL平台指定
returnjpaVA;
}
// 数据源的配置
@Bean
public BasicDataSource dataSource() {
BasicDataSource dataSource =new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8");
dataSource.setUsername("root");
dataSource.setPassword(null);
dataSource.setDefaultAutoCommit(false);
returndataSource;
}
// Spring Data JPA事务配置
@Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager jpaTm =new JpaTransactionManager();
jpaTm.setEntityManagerFactory(entityManagerFactory().getObject());
returnjpaTm;
}
2、Model
User.java:
@Entity
@Table(name = "user")
public class User {
private Stringid;
private Stringusername;
private Stringpassword;
private Stringmobile;
private Stringemail;
@Id
@GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid",strategy="uuid")
public String getId() {
return id;
}
.....
}
3、Dao
UserDao.java:
public interface UserDao {
// 新增记录
void save(Useruser);
// 修改记录
void update(Useruser);
// 根据用户名查询
User findUserByID(User user);
// 查询所有记录
List<User> findUsersNoPage();
// 删除一条记录
void delete(Useruser);
}
UserDaoImpl.java:
@Repository("UserDaoImpl")
public class UserDaoImpl implements UserDao {
@PersistenceContext
private EntityManagerem;
@Override
public void save(User user) {
em.persist(user);
}
@Override
public void update(User user) {
em.persist(em.merge(user));
}
@Override
public User findUserByID(Useruser) {
returnem.find(User.class,user.getId());
}
@Override
public List<User> findUsersNoPage() {
String queryString = "select * from user";
Query query = em.createNativeQuery(queryString,User.class);
List<?> result = query.getResultList();
List<User> users = new ArrayList<User>();
if (result !=null) {
Iterator<?> iterator =result.iterator();
while (iterator.hasNext()) {
User user = (User)iterator.next();
users.add(user);
}
}
returnusers;
}
@Override
public void delete(User user) {
em.remove(em.merge(user));
}
}
这里的@Repository注解,是Spring支持的初始化标记注解,容器初始化扫描时,会自动扫描到该标记的Dao服务实体,进而初始化。另外,这里使用的persist、find、remove及merge等均是EntityManager提供的原生API,这里不做详细介绍,有兴趣的读者可自行查阅资料学习。
4、Service
UserService.java:
@Service("UserService")
public class UserService {
@Autowired
private UserDaouserDao;
// 新增记录
@Transactional
public void saveUser(User user) {
userDao.save(user);
}
// 更新记录
@Transactional
public void updateUser(User user) {
User result = findUserByID(user);
result.setUsername(user.getUsername());
result.setPassword(user.getPassword());
result.setEmail(user.getEmail());
result.setMobile(user.getMobile());
}
// 根据用户名查询记录
public User findUserByID(Useruser) {
returnuserDao.findUserByID(user);
}
// 查询所有记录
public List<User> findUsersNoPage() {
returnuserDao.findUsersNoPage();
}
// 根据用户名删除记录
@Transactional
public void delete(User user) {
userDao.delete(user);
}
}
这里的@Service与上面的@Respository类似,暂且不做细节上差别说明。
三、用JPA方式实现CURD
上面的准备工作完成后,接下来我们就可以编写CURD的程序代码了。
1、控制器
UserController.java:
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
UserServiceuserService;
// 操作页面
@RequestMapping(value="/show",method=RequestMethod.GET)
public ModelAndView show()throws Exception {
// 业务逻辑处理
List<User> result = userService.findUsersNoPage();
// 页面数据渲染
ModelAndView mav = new ModelAndView("test/user_operation");
mav.addObject("result",result);
returnmav;
}
// 新增记录
@RequestMapping(value="/save",method=RequestMethod.POST)
public ModelAndView save(HttpServletRequestrequest) throws Exception {
User user = new User();
user.setUsername(request.getParameter("username"));
user.setPassword(request.getParameter("password"));
user.setMobile(request.getParameter("mobile"));
user.setEmail(request.getParameter("email"));
// 业务逻辑处理
userService.saveUser(user);
// 页面数据渲染
ModelAndView mav = new ModelAndView("test/user_operation");
mav.addObject("result",userService.findUsersNoPage());
returnmav;
}
// 更新记录
@RequestMapping(value="/update",method=RequestMethod.POST)
public ModelAndView update(HttpServletRequestrequest) throws Exception {
User user = new User();
user.setId(request.getParameter("id"));
user.setUsername(request.getParameter("username"));
user.setPassword(request.getParameter("password"));
user.setMobile(request.getParameter("mobile"));
user.setEmail(request.getParameter("email"));
// 业务逻辑处理
userService.updateUser(user);
// 页面数据渲染
ModelAndView mav = new ModelAndView("test/user_operation");
mav.addObject("result",userService.findUsersNoPage());
returnmav;
}
// 根据ID查询
@RequestMapping(value="/find",method=RequestMethod.GET)
public ModelAndView find(HttpServletRequestrequest) throws Exception {
User user = new User();
user.setId(request.getParameter("id"));
// 业务逻辑处理
Useruser2 = userService.findUserByID(user);
List<User>result = new ArrayList<User>();
result.add(user2);
// 页面数据渲染
ModelAndView mav = new ModelAndView("test/user_operation");
mav.addObject("result",result);
returnmav;
}
// 根据ID删除记录
@RequestMapping(value="/delete",method=RequestMethod.GET)
public ModelAndView delete(HttpServletRequestrequest) throws Exception {
User user = new User();
user.setId(request.getParameter("id"));
// 业务逻辑处理
userService.delete(user);
// 页面数据渲染
ModelAndView mav = new ModelAndView("test/user_operation");
mav.addObject("result",userService.findUsersNoPage());
returnmav;
}
}
2、测试页面
user_operation.jsp:
<%@ page language="java"contentType="text/html;charset=UTF-8"pageEncoding="UTF-8"%>
<%@ taglib prefix="c"uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPEhtmlPUBLIC "-//W3C//DTDXHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<scripttype="text/javascript"src="${pageContext.request.contextPath}/resources/js/jquery.min.js"></script>
<scripttype="text/javascript"src="${pageContext.request.contextPath}/resources/js/jquery.form.js"></script>
<style>
.input {width:98%;height:20px;}
</style>
</head>
<body>
<scripttype="text/javascript">
// 显示新增记录视图
function create_show(){
$("#id_mod_record").hide();
$("#id_add_record").show();
}
// 显示更新记录视图
function update_show(id,username,password,email,mobile){
$("#id_form_val").val(id);
$("#username_form_val").val(username);
$("#password_form_val").val(password);
$("#email_form_val").val(email);
$("#mobile_form_val").val(mobile);
$("#id_add_record").hide();
$("#id_mod_record").show();
}
// 根据ID查询单条记录
function find() {
var id = $("#id_search_val").val();
window.location.href= "/spring-orm-jpa/user/find?id="+id;
}
</script>
<div>
<!-- 根据ID查询记录 -->
<div>
<table>
<tr>
<tdalign="left"><pstyle="line-height:10px;font-size:14px;">ID:</p></td>
<tdalign="left"><inputstyle="width:240px;"type="text"name="id"id="id_search_val"value="402881e85fce9aac015fce9aded30000"placeholder="id"/></td>
<td> <input type="button"onclick="javascript:find();"value="点击根据ID查询"/></td>
<td><inputstyle="margin-left:386px;"type="button"onclick="javascript:create_show();"value="点击新增"/></td>
</tr>
</table>
</div>
<!-- 所有记录列表 -->
<div>
<tableborder="1px;"cellspacing="0"cellpadding="0">
<tr><td>ID</td><td>UserName</td><td>Password</td><td>Email</td><td>Mobile</td><td>操作</td></tr>
<c:forEachitems="${result}"var="item">
<inputtype="hidden"class="c_user_val"value="${item}"></input>
<tr>
<td><c:outvalue="${item.id}"></c:out></td>
<td><c:outvalue="${item.username}"></c:out></td>
<td><c:outvalue="${item.password}"></c:out></td>
<td><c:outvalue="${item.email}"></c:out></td>
<td><c:outvalue="${item.mobile}"></c:out></td>
<td>
<ahref="javascript:update_show('${item.id}','${item.username}','${item.password}','${item.email}','${item.mobile}');"
onclick=""> 编辑 </a>|
<ahref="/spring-orm-jpa/user/delete?id=${item.id}"> 删除 </a>
</td>
</tr>
</c:forEach>
</table>
</div>
<!-- 新增记录 -->
<divid="id_add_record"style="display:block;margin-top:20px;">
<formmethod="post"action="/spring-orm-jpa/user/save">
<tableborder="1px;"cellspacing="0"cellpadding="0"width="400">
<tr>
<tdalign="left"><pstyle="line-height:0px;font-size:14px;">UserName:</p></td>
<tdalign="left"><inputclass="input"type="text"name="username"value="cwteam"placeholder="username"/></td>
</tr>
<tr>
<tdalign="left"><pstyle="line-height:0px;font-size:14px;">Password:</p></td>
<tdalign="left"><inputclass="input"type="password"name="password"value="123456"placeholder="password"/></td>
</tr>
<tr>
<tdalign="left"><pstyle="line-height:0px;font-size:14px;">Mobile:</p></td>
<tdalign="left"><inputclass="input"type="text"name="mobile"value="18721663282"placeholder="mobile"/></td>
</tr>
<tr>
<tdalign="left"><pstyle="line-height:0px;font-size:14px;">Email:</p></td>
<tdalign="left"><inputclass="input"type="text"name="email"value="[email protected]"placeholder="email"/></td>
</tr>
</table>
<inputstyle="margin-left:160px;margin-top:10px;"type="submit"value="新增记录"/>
</form>
</div>
<!-- 更新记录 -->
<divid="id_mod_record"style="display:none;margin-top:20px;">
<formmethod="post"action="/spring-orm-jpa/user/update">
<tableborder="1px;"cellspacing="0"cellpadding="0"width="400">
<tr>
<tdalign="left"><pstyle="line-height:10px;font-size:14px;">ID:</p></td>
<tdalign="left"><inputclass="input"id="id_form_val"type="text"name="id"value="402881e85fce9aac015fce9aded30000"placeholder="id"/></td>
</tr>
<tr>
<tdalign="left"><pstyle="line-height:10px;font-size:14px;">UserName:</p></td>
<tdalign="left"><inputclass="input"id="username_form_val"type="text"name="username"value="cwteam2"placeholder="username"/></td>
</tr>
<tr>
<tdalign="left"><pstyle="line-height:0px;font-size:14px;">Password:</p></td>
<tdalign="left"><inputclass="input"id="password_form_val"type="password"name="password"value="1234567"placeholder="password"/></td>
</tr>
<tr>
<tdalign="left"><pstyle="line-height:0px;font-size:14px;">Mobile:</p></td>
<tdalign="left"><inputclass="input"id="mobile_form_val"type="text"name="mobile"value="18721663283"placeholder="mobile"/></td>
</tr>
<tr>
<tdalign="left"><pstyle="line-height:0px;font-size:14px;">Email:</p></td>
<tdalign="left"><inputclass="input"id="email_form_val"type="text"name="email"value="[email protected]"placeholder="email"/></td>
</tr>
</table>
<inputstyle="margin-left:160px;margin-top:10px;"type="submit"value="更新记录"/>
</form>
</div>
</div>
</body>
</html>
3、验证结果
整体的结果:
A、新增一条记录
新增了cwteam7记录
B、修改一条记录
更新了cwteam6记录,修改了email值。
C、删除一条记录
删除了cwteam5记录
D、根据ID查询记录:
根据ID查询了cwteam4的单条记录信息
好了,由于作者水平有限,如有不正确或是误导的地方,请不吝指出讨论(技术交流群:497552060(新))