Java Spring/Hibernate/HSQLDB组合的会话/事务问题
出于培训目的,我目前正在重写我的应用程序,以使用Spring和Hibernate的组合来访问我的本地HSQLDB,而不仅仅是通过JDBC进行访问 我认为我的大部分工作正常,当我为测试目的在我的主方法上执行一些方法时,一切似乎都很好。然而,一旦我想通过@Transactional启用事务处理,整个过程就会停止工作,告诉我没有连接存在 我已经在stackoverflow上尝试了在类似问题中给出的一些解决方案,但没有一个对我有效 首先,完整的堆栈跟踪: 下面是我的类和配置文件: 数据源配置:Java Spring/Hibernate/HSQLDB组合的会话/事务问题,java,spring,hibernate,spring-mvc,transactions,Java,Spring,Hibernate,Spring Mvc,Transactions,出于培训目的,我目前正在重写我的应用程序,以使用Spring和Hibernate的组合来访问我的本地HSQLDB,而不仅仅是通过JDBC进行访问 我认为我的大部分工作正常,当我为测试目的在我的主方法上执行一些方法时,一切似乎都很好。然而,一旦我想通过@Transactional启用事务处理,整个过程就会停止工作,告诉我没有连接存在 我已经在stackoverflow上尝试了在类似问题中给出的一些解决方案,但没有一个对我有效 首先,完整的堆栈跟踪: 下面是我的类和配置文件: 数据源配置: <
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="net.sourceforge.jtds.jdbc.Driver" />
<property name="url" value="jdbc:hsqldb:file:C:\\dev\\source\\productionDB\\productionDB;shutdown=true" />
<property name="username" value="admin" />
<property name="password" value="admin" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="exercise.java.basics.storage" />
<property name="mappingLocations">
<list>
<value>classpath:hibernate/Warehouse.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect"> org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<tx:annotation-driven transaction-manager="txManager"/>
</beans>
DAO实现:
@Transactional
@Repository
public class WarehouseDAOImpl implements WarehouseDAO {
private DataSource dataSource;
@Autowired
private SessionFactory sessionFactory;
public void setDataSource( final DataSource dataSource ) {
this.dataSource = dataSource;
}
public void setSessionFactory( final SessionFactory sessionFactory ) {
this.sessionFactory = sessionFactory;
}
public void initializeWarehouse() {
String initProductsSQL = "INSERT INTO WAREHOUSE(product_name, product_count) VALUES (?, 0)";
Connection conn = null;
try {
conn = DataSourceUtils.getConnection( this.dataSource );
Statement stmt = conn.createStatement();
PreparedStatement ps = conn.prepareStatement( initProductsSQL );
ps.setString( 1, String.valueOf( Product.NAIL ) );
ps.executeUpdate();
ps.setString( 1, String.valueOf( Product.SCREW ) );
ps.executeUpdate();
ps.setString( 1, String.valueOf( Product.FINALPRODUCT ) );
ps.executeUpdate();
ps.close();
} catch ( SQLException e ) {
throw new RuntimeException( e );
} finally {
if ( conn != null ) {
try {
conn.close();
} catch ( SQLException e ) {
e.printStackTrace();
}
}
}
}
public void storeProducts( final Product product, final int count ) {
String updateProductCountSQL = "UPDATE WAREHOUSE SET product_count = product_count + " + count
+ " WHERE product_name = '" + product + "'";
Connection conn = null;
try {
conn = DataSourceUtils.getConnection( this.dataSource );
Statement stmt = conn.createStatement();
stmt.execute( updateProductCountSQL );
stmt.close();
} catch ( SQLException e ) {
throw new RuntimeException( e );
} finally {
if ( conn != null ) {
try {
conn.close();
} catch ( SQLException e ) {
e.printStackTrace();
}
}
}
}
public void removeProducts( final Product product, final int count ) {
String updateProductCountSQL = "UPDATE WAREHOUSE SET product_count = product_count - " + count
+ " WHERE product_name = '" + product + "'";
Connection conn = null;
try {
conn = DataSourceUtils.getConnection( this.dataSource );
Statement stmt = conn.createStatement();
stmt.execute( updateProductCountSQL );
stmt.close();
} catch ( SQLException e ) {
throw new RuntimeException( e );
} finally {
if ( conn != null ) {
try {
conn.close();
} catch ( SQLException e ) {
e.printStackTrace();
}
}
}
}
public void updateStock() {
String getUpdatedStocksSQL = "SELECT * FROM WAREHOUSE WHERE product_name = ? ;";
Connection conn = null;
try {
conn = DataSourceUtils.getConnection( this.dataSource );
PreparedStatement ps = conn.prepareStatement( getUpdatedStocksSQL );
WarehouseNew warehouse = exercise.java.basics.storage.WarehouseNew.getInstance();
ps.setString( 1, String.valueOf( Product.NAIL ) );
ResultSet rsNail = ps.executeQuery();
ps.setString( 1, String.valueOf( Product.SCREW ) );
ResultSet rsScrew = ps.executeQuery();
ps.setString( 1, String.valueOf( Product.FINALPRODUCT ) );
ResultSet rsFinalProduct = ps.executeQuery();
rsNail.next();
rsScrew.next();
rsFinalProduct.next();
warehouse.setNailCount( rsNail.getString( 3 ) );
warehouse.setScrewCount( rsNail.getString( 3 ) );
warehouse.setFinalProductCount( rsNail.getString( 3 ) );
//Debug
System.out.println( rsNail.getInt( 3 ) );
System.out.println( rsScrew.getInt( 3 ) );
System.out.println( rsFinalProduct.getInt( 3 ) );
rsNail.close();
rsScrew.close();
rsFinalProduct.close();
ps.close();
} catch ( SQLException e ) {
throw new RuntimeException( e );
} finally {
if ( conn != null ) {
try {
conn.close();
} catch ( SQLException e ) {
e.printStackTrace();
}
}
}
}
public static void main( final String[] args ) {
ApplicationContext context = new ClassPathXmlApplicationContext( "Spring-Module.xml" );
WarehouseDAO warehouseDAO = (WarehouseDAO) context.getBean( "warehouseDAO" );
// warehouseDAO.initializeWarehouse();
warehouseDAO.updateStock();
warehouseDAO.storeProducts( Product.NAIL, 10 );
warehouseDAO.storeProducts( Product.SCREW, 20 );
warehouseDAO.storeProducts( Product.FINALPRODUCT, 30 );
warehouseDAO.updateStock();
}
}
模型类:
public class WarehouseNew {
private int nailCount;
private int screwCount;
private int finalProductCount;
private int product_ID;
private String product_name;
private int product_count;
private static volatile WarehouseNew instance = null;
public static WarehouseNew getInstance() {
if ( instance == null ) {
synchronized ( WarehouseNew.class ) {
if ( instance == null ) {
instance = new WarehouseNew();
}
}
}
return instance;
}
/**
* Constructor for ...
*/
private WarehouseNew() {
}
/**
* @return the nailCount
*/
public int getNailCount() {
return this.nailCount;
}
/**
* @param string the nailCount to set
*/
public void setNailCount( final String string ) {
this.nailCount = Integer.parseInt( string );
}
/**
* @return the screwCount
*/
public int getScrewCount() {
return this.screwCount;
}
/**
* @param string the screwCount to set
*/
public void setScrewCount( final String string ) {
this.screwCount = Integer.parseInt( string );
}
/**
* @return the finalProductCount
*/
public int getFinalProductCount() {
return this.finalProductCount;
}
/**
* @param string the finalProductCount to set
*/
public void setFinalProductCount( final String string ) {
this.finalProductCount = Integer.parseInt( string );
}
/**
* @return the product_id
*/
public int getProduct_ID() {
return this.product_ID;
}
/**
* @param product_id the product_id to set
*/
public void setProduct_ID( final int product_ID ) {
this.product_ID = product_ID;
}
/**
* @return the product_name
*/
public String getProduct_name() {
return this.product_name;
}
/**
* @param product_name the product_name to set
*/
public void setProduct_name( final String product_name ) {
this.product_name = product_name;
}
/**
* @return the product_count
*/
public int getProduct_count() {
return this.product_count;
}
/**
* @param product_count the product_count to set
*/
public void setProduct_count( final int product_count ) {
this.product_count = product_count;
}
}
我希望有人能给我指出正确的方向。Spring框架和Hibernate对我来说是全新的,我只想让它工作
我真的不明白为什么当我不使用@Transactional注释时,数据库访问会起作用,但是我说在使用它时没有连接。。。这对我来说毫无意义
致意
达扎
编辑:根据使用sessionFactory的建议进行更改。但错误仍然是一样的
// Experimental
this.sessionFactory.getCurrentSession().doWork(
new Work() {
public void execute( final Connection connection ) throws SQLException {
try {
String getUpdatedStocksSQL = "SELECT * FROM WAREHOUSE WHERE product_name = ? ;";
PreparedStatement ps = connection.prepareStatement( getUpdatedStocksSQL );
WarehouseNew warehouse = exercise.java.basics.storage.WarehouseNew.getInstance();
ps.setString( 1, String.valueOf( Product.NAIL ) );
ResultSet rsNail = ps.executeQuery();
ps.setString( 1, String.valueOf( Product.SCREW ) );
ResultSet rsScrew = ps.executeQuery();
ps.setString( 1, String.valueOf( Product.FINALPRODUCT ) );
ResultSet rsFinalProduct = ps.executeQuery();
rsNail.next();
rsScrew.next();
rsFinalProduct.next();
warehouse.setNailCount( rsNail.getString( 3 ) );
warehouse.setScrewCount( rsNail.getString( 3 ) );
warehouse.setFinalProductCount( rsNail.getString( 3 ) );
System.out.println( rsNail.getInt( 3 ) );
System.out.println( rsScrew.getInt( 3 ) );
System.out.println( rsFinalProduct.getInt( 3 ) );
rsNail.close();
rsScrew.close();
rsFinalProduct.close();
ps.close();
} catch ( SQLException e ) {
throw new RuntimeException( e );
} finally {
if ( connection != null ) {
try {
connection.close();
} catch ( SQLException e ) {
e.printStackTrace();
}
}
}
}
} );
// !Experimental
我认为您的jdbc驱动程序URL不正确: 对于HSQL,它是
org.hsqldb.jdbcDriver
你好像有
<property name="driverClassName" value="net.sourceforge.jtds.jdbc.Driver" />
这是一个MS-SQL/Sybase驱动程序类
此时@Transaction注释失败的主要原因是您使用的是hibernate事务管理器(因此只有在开始使用会话工厂时才起作用)
要使旧的jdbc代码正常工作,您需要有如下内容:
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
另一种方法是用sessionFactory.getCurrentSession().connection()替换dataSource utils.getConnection(this.dataSource)。事实上,这是您最好使用的方法。谢谢,我们将尝试在此基础上进行更改。我想使用Hibernate,所以我想我将尝试sessionFactory方法。不过,有一个问题,为什么我现在不使用sessionFactory?据我所知,我通过setter注入将sessionFactory注入到我的DAO中。那么我应该已经在使用它了?根据您的代码,当您获得数据库连接时,它是通过
conn=DataSourceUtils.getConnection(this.dataSource)完成的
。这是通过数据源而不是SessionFactory建立的连接。好的。我认为使用@AutoWire和setter注入弹簧可以自行处理所有事情。我不知道session=connection。我尝试实现了你的建议,但一直收到相同的错误消息。有关代码,请参阅我的原始帖子。我发现了令人惊讶的地方不过,sysos实际上会将正确的值打印到控制台,并且只有在打印完成后才会发生错误。查看实验代码,我认为您不需要在最后关闭数据库连接。我的理解是,hibernate将连接作为参数传递,因此它将为您管理连接您需要了解如何打开和关闭。由以下原因引起的异常:org.hsqldb.HsqlException:connection exception:connection not existence
,可能是因为连接过早关闭(由于最后的代码),但这只是我试图在异常和代码之间进行推理:)
// Experimental
this.sessionFactory.getCurrentSession().doWork(
new Work() {
public void execute( final Connection connection ) throws SQLException {
try {
String getUpdatedStocksSQL = "SELECT * FROM WAREHOUSE WHERE product_name = ? ;";
PreparedStatement ps = connection.prepareStatement( getUpdatedStocksSQL );
WarehouseNew warehouse = exercise.java.basics.storage.WarehouseNew.getInstance();
ps.setString( 1, String.valueOf( Product.NAIL ) );
ResultSet rsNail = ps.executeQuery();
ps.setString( 1, String.valueOf( Product.SCREW ) );
ResultSet rsScrew = ps.executeQuery();
ps.setString( 1, String.valueOf( Product.FINALPRODUCT ) );
ResultSet rsFinalProduct = ps.executeQuery();
rsNail.next();
rsScrew.next();
rsFinalProduct.next();
warehouse.setNailCount( rsNail.getString( 3 ) );
warehouse.setScrewCount( rsNail.getString( 3 ) );
warehouse.setFinalProductCount( rsNail.getString( 3 ) );
System.out.println( rsNail.getInt( 3 ) );
System.out.println( rsScrew.getInt( 3 ) );
System.out.println( rsFinalProduct.getInt( 3 ) );
rsNail.close();
rsScrew.close();
rsFinalProduct.close();
ps.close();
} catch ( SQLException e ) {
throw new RuntimeException( e );
} finally {
if ( connection != null ) {
try {
connection.close();
} catch ( SQLException e ) {
e.printStackTrace();
}
}
}
}
} );
// !Experimental
org.hsqldb.jdbcDriver
<property name="driverClassName" value="net.sourceforge.jtds.jdbc.Driver" />
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>