我的 Spring+Hibernate 服务器小程序中出现 TransactionRequiredException
I'm getting an TransactionRequiredException in my Spring+Hibernate server applet
我一直在构建一个 Spring MVC 应用程序,它使用 SpringDataJPA 和休眠,并利用 MySQL。从某个时候开始,我在主网页(名为 'main')上收到了一个 TransactionRequiredException,我无法摆脱它。你能告诉我我的配置/代码哪里出错了吗?
appconfig-data.xml
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"
value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- Configure the entity manager factory bean -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.ajwt.entities" />
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<!-- Configure the transaction manager bean -->
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory"
ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven
transaction-manager="transactionManager" />
<!-- Configure Spring Data JPA and set the base package of the repository
interfaces -->
<!-- Configure Spring Data JPA and set the base package of the repository
interfaces -->
<jpa:repositories base-package="com.ajwt.repositories" />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.ajwt.entities" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
堆栈跟踪
Hibernate: select projects0_.id as id1_2_, projects0_.description as
descript2_2_, projects0_.duedate as duedate3_2_, projects0_.grade as
grade4_2_, projects0_.pname as pname5_2_, projects0_.sid as sid6_2_,
projects0_.state as state7_2_ from ajwt.projects projects0_
אפר׳ 17, 2019 3:14:24 לפנה״צ org.apache.catalina.core.StandardWrapperValve
invoke
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/ajwt]
threw exception [Request processing failed; nested exception is
javax.persistence.TransactionRequiredException: no transaction is in
progress] with root cause
javax.persistence.TransactionRequiredException: no transaction is in
progress
控制器
@RequestMapping(value = "/", method = RequestMethod.GET)
public String defaultPage(Model model) {
return "redirect:/main";
}
@RequestMapping(value = { "/main" }, method = RequestMethod.GET)
public String welcome(Model model) {
model.addAttribute("addProject", new Projects());
model.addAttribute("projectList", projectService.getAllProjects());
model.addAttribute("availableProjectList",
projectService.getAvailableProjects());
model.addAttribute("scholarList", userService.getScholars());
model.addAttribute("technologiesList",
techService.getAllTechnologies());
return "main";
}
@RequestMapping(value = "/main", method = RequestMethod.POST)
public String addProject(@ModelAttribute("addProject") Projects project,
BindingResult bindingResult, ModelMap model) {
projectService.save(project);
return "redirect:/main";
}
项目服务
@Service("projectService")
public class ProjectServiceImpl implements ProjectService {
@Autowired
private ProjectRepository projectRepository;
@Autowired
private SessionFactory sessionFactory;
public void save(Projects project) {
projectRepository.save(project);
}
@Transactional
@Override
public List<Projects> getAllProjects() {
TypedQuery<Projects> query = sessionFactory.getCurrentSession().createQuery("from Projects");
return query.getResultList();
}
@Transactional
@Override
public List<Projects> getAvailableProjects() {
TypedQuery<Projects> query = sessionFactory.getCurrentSession()
.createQuery("from Projects where state = 'PROJECT_AVAIL'");
return query.getResultList();
}
@Transactional
@Override
public List<Projects> getMyProjects(int id) {
TypedQuery<Projects> query = sessionFactory.getCurrentSession().createQuery("from Projects");
return query.getResultList();
}
@Transactional
@Override
public void addProject(Projects project) {
projectRepository.save(project);
}
}
技术服务
@Service("technologiesService")
public class TechServiceImpl implements TechService {
@Autowired
private ProjectRepository projectRepository;
@Autowired
private SessionFactory sessionFactory;
@Override
@Transactional
public List<Technologies> getAllTechnologies() {
TypedQuery<Technologies> query = sessionFactory.getCurrentSession().createQuery("select tech from Technologies");
return query.getResultList();
}
}
技术
package com.ajwt.entities;
// Generated 17 באפר׳ 2019, 2:45:49 by Hibernate Tools 4.3.5.Final
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
/**
* Technologies generated by hbm2java
*/
@Entity
@Table(name = "technologies", catalog = "ajwt")
public class Technologies implements java.io.Serializable {
private Integer id;
private String tech;
private Set<Projects> projectses = new HashSet<Projects>(0);
public Technologies() {
}
public Technologies(String tech) {
this.tech = tech;
}
public Technologies(String tech, Set<Projects> projectses) {
this.tech = tech;
this.projectses = projectses;
}
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "tech", nullable = false, length = 45)
public String getTech() {
return this.tech;
}
public void setTech(String tech) {
this.tech = tech;
}
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "project_technologies", catalog = "ajwt", joinColumns = {
@JoinColumn(name = "tid", nullable = false, updatable = false) }, inverseJoinColumns = {
@JoinColumn(name = "pid", nullable = false, updatable = false) })
public Set<Projects> getProjectses() {
return this.projectses;
}
public void setProjectses(Set<Projects> projectses) {
this.projectses = projectses;
}
}
main.jsp
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<meta name="description" content="">
<meta name="author" content="Edward Romanenco">
<head>
<title>Administrator Console</title>
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
crossorigin="anonymous">
<link href="${contextPath}/resources/css/common.css" rel="stylesheet">
</head>
<body>
<h2>Project Management Screen</h2>
<c:if test="${pageContext.request.userPrincipal.name != null}">
<form id="logoutForm" method="POST" action="${contextPath}/logout">
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
</form>
<h6>
Welcome ${pageContext.request.userPrincipal.name}! | <a
onclick="document.forms['logoutForm'].submit()">Logout</a>
</h6>
</c:if>
<div>
<h3>My Projects</h3>
<c:choose>
<c:when test="${!empty projectList}">
<table class="data">
<tr>
<th>Project Name</th>
<th>Due Date</th>
</tr>
<c:forEach items="${projectList}" var="project">
<tr>
<td>${project.pname}</td>
<td><c:choose>
<c:when test="${project.duedate}!=null">${project.duedate}</c:when>
<c:otherwise>No Due Date Yet</c:otherwise>
</c:choose></td>
<!--<td><a href="edit/${project.id}">Edit</a></td>
<td><a href="delete/${project.id}">Delete</a></td>-->
</tr>
</c:forEach>
</table>
</c:when>
<c:otherwise>
You don't participate in any project, look over the available projects section to start!
</c:otherwise>
</c:choose>
</div>
<div>
<h3>Available Projects</h3>
<c:choose>
<c:when test="${!empty availableProjectList}">
<table class="data">
<tr>
<th>Project Name</th>
<th>Due Date</th>
</tr>
<c:forEach items="${availableProjectList}" var="project">
<tr>
<td>${project.pname}</td>
<td>${project.duedate}</td>
<!-- <td><a href="join/${project.id}">join</a></td>-->
</tr>
</c:forEach>
</table>
</c:when>
<c:otherwise>
There are no available projects currently, make sure you come back soon as those are added daily!
</c:otherwise>
</c:choose>
</div>
<h3>Suggest Projects</h3>
<div>
<form:form method="POST" modelAttribute="addProject">
<table>
<spring:bind path="pname">
<tr>
<td><form:label path="pname">Project Name</form:label></td>
<td><form:input path="pname" /></td>
</tr>
</spring:bind>
<spring:bind path="description">
<tr>
<td><form:label path="description">Description</form:label></td>
<td><form:textarea path="description" rows="5" cols="25" /></td>
</tr>
</spring:bind>
<spring:bind path="sid">
<tr>
<td><form:label path="sid">Scholar:</form:label></td>
<td><form:select id="projectSelect" name="userId" path="sid">
<c:forEach var="theUser" items="${scholarList}">
<form:option value="${scholarList.id}">
<c:out value="${scholarList.fname} ${scholarList.lname}" />
</form:option>
</c:forEach>
</form:select></td>
</tr>
</spring:bind>
<spring:bind path="technologieses">
<tr>
<td><form:label path="technologieses">Technologies:</form:label></td>
<td><form:checkboxes items="${technologiesList}"
path="technologieses" /></td>
</tr>
</spring:bind>
<tr>
<td colspan="2"><input type="submit" value="Submit" /></td>
</tr>
</table>
</form:form>
</div>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script
src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
crossorigin="anonymous"></script>
</body>
</html>
问题是你们都配置了一个EntityManagerFactory
和一个SessionFactory
。您现在有 2 个单独的实例来管理您的依赖项。您配置的事务管理器适用于 JPA 而不是普通的 Hibernate。
不使用普通的 Hibernate,而是使用 JPA。从您的配置中删除 SessionFactory
的定义,而不是自动装配 SessionFactory
使用 JPA 提供的 EntityManager
。
@Service("technologiesService")
public class TechServiceImpl implements TechService {
@Autowired
private ProjectRepository projectRepository;
@PersistenceContext
private EntityManager entityManager;
@Override
@Transactional
public List<Technologies> getAllTechnologies() {
return entityManager.createQuery("SELECT t FROM Technologies t").getResultList();
}
}
Spring 将负责注入当前绑定 EntityManager
。
我一直在构建一个 Spring MVC 应用程序,它使用 SpringDataJPA 和休眠,并利用 MySQL。从某个时候开始,我在主网页(名为 'main')上收到了一个 TransactionRequiredException,我无法摆脱它。你能告诉我我的配置/代码哪里出错了吗?
appconfig-data.xml
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"
value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- Configure the entity manager factory bean -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.ajwt.entities" />
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<!-- Configure the transaction manager bean -->
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory"
ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven
transaction-manager="transactionManager" />
<!-- Configure Spring Data JPA and set the base package of the repository
interfaces -->
<!-- Configure Spring Data JPA and set the base package of the repository
interfaces -->
<jpa:repositories base-package="com.ajwt.repositories" />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.ajwt.entities" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
堆栈跟踪
Hibernate: select projects0_.id as id1_2_, projects0_.description as
descript2_2_, projects0_.duedate as duedate3_2_, projects0_.grade as
grade4_2_, projects0_.pname as pname5_2_, projects0_.sid as sid6_2_,
projects0_.state as state7_2_ from ajwt.projects projects0_
אפר׳ 17, 2019 3:14:24 לפנה״צ org.apache.catalina.core.StandardWrapperValve
invoke
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/ajwt]
threw exception [Request processing failed; nested exception is
javax.persistence.TransactionRequiredException: no transaction is in
progress] with root cause
javax.persistence.TransactionRequiredException: no transaction is in
progress
控制器
@RequestMapping(value = "/", method = RequestMethod.GET)
public String defaultPage(Model model) {
return "redirect:/main";
}
@RequestMapping(value = { "/main" }, method = RequestMethod.GET)
public String welcome(Model model) {
model.addAttribute("addProject", new Projects());
model.addAttribute("projectList", projectService.getAllProjects());
model.addAttribute("availableProjectList",
projectService.getAvailableProjects());
model.addAttribute("scholarList", userService.getScholars());
model.addAttribute("technologiesList",
techService.getAllTechnologies());
return "main";
}
@RequestMapping(value = "/main", method = RequestMethod.POST)
public String addProject(@ModelAttribute("addProject") Projects project,
BindingResult bindingResult, ModelMap model) {
projectService.save(project);
return "redirect:/main";
}
项目服务
@Service("projectService")
public class ProjectServiceImpl implements ProjectService {
@Autowired
private ProjectRepository projectRepository;
@Autowired
private SessionFactory sessionFactory;
public void save(Projects project) {
projectRepository.save(project);
}
@Transactional
@Override
public List<Projects> getAllProjects() {
TypedQuery<Projects> query = sessionFactory.getCurrentSession().createQuery("from Projects");
return query.getResultList();
}
@Transactional
@Override
public List<Projects> getAvailableProjects() {
TypedQuery<Projects> query = sessionFactory.getCurrentSession()
.createQuery("from Projects where state = 'PROJECT_AVAIL'");
return query.getResultList();
}
@Transactional
@Override
public List<Projects> getMyProjects(int id) {
TypedQuery<Projects> query = sessionFactory.getCurrentSession().createQuery("from Projects");
return query.getResultList();
}
@Transactional
@Override
public void addProject(Projects project) {
projectRepository.save(project);
}
}
技术服务
@Service("technologiesService")
public class TechServiceImpl implements TechService {
@Autowired
private ProjectRepository projectRepository;
@Autowired
private SessionFactory sessionFactory;
@Override
@Transactional
public List<Technologies> getAllTechnologies() {
TypedQuery<Technologies> query = sessionFactory.getCurrentSession().createQuery("select tech from Technologies");
return query.getResultList();
}
}
技术
package com.ajwt.entities;
// Generated 17 באפר׳ 2019, 2:45:49 by Hibernate Tools 4.3.5.Final
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
/**
* Technologies generated by hbm2java
*/
@Entity
@Table(name = "technologies", catalog = "ajwt")
public class Technologies implements java.io.Serializable {
private Integer id;
private String tech;
private Set<Projects> projectses = new HashSet<Projects>(0);
public Technologies() {
}
public Technologies(String tech) {
this.tech = tech;
}
public Technologies(String tech, Set<Projects> projectses) {
this.tech = tech;
this.projectses = projectses;
}
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "tech", nullable = false, length = 45)
public String getTech() {
return this.tech;
}
public void setTech(String tech) {
this.tech = tech;
}
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "project_technologies", catalog = "ajwt", joinColumns = {
@JoinColumn(name = "tid", nullable = false, updatable = false) }, inverseJoinColumns = {
@JoinColumn(name = "pid", nullable = false, updatable = false) })
public Set<Projects> getProjectses() {
return this.projectses;
}
public void setProjectses(Set<Projects> projectses) {
this.projectses = projectses;
}
}
main.jsp
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<meta name="description" content="">
<meta name="author" content="Edward Romanenco">
<head>
<title>Administrator Console</title>
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
crossorigin="anonymous">
<link href="${contextPath}/resources/css/common.css" rel="stylesheet">
</head>
<body>
<h2>Project Management Screen</h2>
<c:if test="${pageContext.request.userPrincipal.name != null}">
<form id="logoutForm" method="POST" action="${contextPath}/logout">
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
</form>
<h6>
Welcome ${pageContext.request.userPrincipal.name}! | <a
onclick="document.forms['logoutForm'].submit()">Logout</a>
</h6>
</c:if>
<div>
<h3>My Projects</h3>
<c:choose>
<c:when test="${!empty projectList}">
<table class="data">
<tr>
<th>Project Name</th>
<th>Due Date</th>
</tr>
<c:forEach items="${projectList}" var="project">
<tr>
<td>${project.pname}</td>
<td><c:choose>
<c:when test="${project.duedate}!=null">${project.duedate}</c:when>
<c:otherwise>No Due Date Yet</c:otherwise>
</c:choose></td>
<!--<td><a href="edit/${project.id}">Edit</a></td>
<td><a href="delete/${project.id}">Delete</a></td>-->
</tr>
</c:forEach>
</table>
</c:when>
<c:otherwise>
You don't participate in any project, look over the available projects section to start!
</c:otherwise>
</c:choose>
</div>
<div>
<h3>Available Projects</h3>
<c:choose>
<c:when test="${!empty availableProjectList}">
<table class="data">
<tr>
<th>Project Name</th>
<th>Due Date</th>
</tr>
<c:forEach items="${availableProjectList}" var="project">
<tr>
<td>${project.pname}</td>
<td>${project.duedate}</td>
<!-- <td><a href="join/${project.id}">join</a></td>-->
</tr>
</c:forEach>
</table>
</c:when>
<c:otherwise>
There are no available projects currently, make sure you come back soon as those are added daily!
</c:otherwise>
</c:choose>
</div>
<h3>Suggest Projects</h3>
<div>
<form:form method="POST" modelAttribute="addProject">
<table>
<spring:bind path="pname">
<tr>
<td><form:label path="pname">Project Name</form:label></td>
<td><form:input path="pname" /></td>
</tr>
</spring:bind>
<spring:bind path="description">
<tr>
<td><form:label path="description">Description</form:label></td>
<td><form:textarea path="description" rows="5" cols="25" /></td>
</tr>
</spring:bind>
<spring:bind path="sid">
<tr>
<td><form:label path="sid">Scholar:</form:label></td>
<td><form:select id="projectSelect" name="userId" path="sid">
<c:forEach var="theUser" items="${scholarList}">
<form:option value="${scholarList.id}">
<c:out value="${scholarList.fname} ${scholarList.lname}" />
</form:option>
</c:forEach>
</form:select></td>
</tr>
</spring:bind>
<spring:bind path="technologieses">
<tr>
<td><form:label path="technologieses">Technologies:</form:label></td>
<td><form:checkboxes items="${technologiesList}"
path="technologieses" /></td>
</tr>
</spring:bind>
<tr>
<td colspan="2"><input type="submit" value="Submit" /></td>
</tr>
</table>
</form:form>
</div>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script
src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
crossorigin="anonymous"></script>
</body>
</html>
问题是你们都配置了一个EntityManagerFactory
和一个SessionFactory
。您现在有 2 个单独的实例来管理您的依赖项。您配置的事务管理器适用于 JPA 而不是普通的 Hibernate。
不使用普通的 Hibernate,而是使用 JPA。从您的配置中删除 SessionFactory
的定义,而不是自动装配 SessionFactory
使用 JPA 提供的 EntityManager
。
@Service("technologiesService")
public class TechServiceImpl implements TechService {
@Autowired
private ProjectRepository projectRepository;
@PersistenceContext
private EntityManager entityManager;
@Override
@Transactional
public List<Technologies> getAllTechnologies() {
return entityManager.createQuery("SELECT t FROM Technologies t").getResultList();
}
}
Spring 将负责注入当前绑定 EntityManager
。