在Spring Petclinic中切换数据库

4

我正在尝试在spring宠物诊所示例应用程序中从hsql切换到MySQL。有人能告诉我我做错了什么吗?

我按照petclinic_db_setup_mysql.txt文件中的说明操作,并确认数据库已在mysql中正确创建,但是当我尝试在eclipse中从tomcat 7运行应用程序时,出现以下错误:

org.springframework.beans.factory.BeanDefinitionStoreException:  
Invalid bean definition with name 'entityManagerFactory' defined in class path resource  
[spring/business-config.xml]:  
Could not resolve placeholder 'jpa.showSql' in string value "${jpa.showSql}"

以下是business-config中相关的代码:

   <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
          p:dataSource-ref="dataSource">
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
                  p:database="${jpa.database}" p:showSql="${jpa.showSql}"/>
            <!-- the 'database' parameter refers to the database dialect being used.
                By default, Hibernate will use a 'HSQL' dialect because 'jpa.database' has been set to 'HSQL'
                inside file spring/data-access.properties
             -->
        </property>
        <!-- gDickens: BOTH Persistence Unit and Packages to Scan are NOT compatible, persistenceUnit will win -->
        <property name="persistenceUnitName" value="petclinic"/>
        <property name="packagesToScan" value="org.springframework.samples.petclinic"/>
    </bean>

这里是data-access.properties的内容:

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/petclinic
jdbc.username=root
jdbc.password=some_pwd

# Properties that control the population of schema and data for a new data source
jdbc.initLocation=classpath:db/mysql/initDB.sql
jdbc.dataLocation=classpath:db/mysql/populateDB.sql

# Property that determines which Hibernate dialect to use
# (only applied with "applicationContext-hibernate.xml")
hibernate.dialect=org.hibernate.dialect.MySQLDialect

# Property that determines which database to use with an AbstractJpaVendorAdapter
jpa.database=MYSQL
jpa.showSql = true #Added at Dan's suggestion, but new error occurs now.  

编辑:

我已经按照上面的示例添加了 jpa.showSql=true,但现在出现了以下新的错误信息:

ERROR ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException:  
Error creating bean with name 'org.springframework.jdbc.datasource.init.DataSourceInitializer#0':  
Invocation of init method failed; nested exception is org.springframework.dao.DataAccessResourceFailureException:  
Failed to execute database script; nested exception is org.springframework.jdbc.CannotGetJdbcConnectionException:  
Could not get JDBC Connection;  
nested exception is java.sql.SQLException: com.mysql.jdbc.Driver

我确认数据库密码是正确的(不是上面的虚假密码),而且我能够在MySQL命令行客户端中浏览数据库。因此,问题在于连接Web应用程序到数据库上。有没有进一步的建议?

根据Sotirios的请求,这里提供了同样错误的更完整的堆栈跟踪:

Nov 28, 2013 1:51:31 PM org.apache.catalina.core.StandardContext listenerStart
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.jdbc.datasource.init.DataSourceInitializer#0': Invocation of init method failed; nested exception is org.springframework.dao.DataAccessResourceFailureException: Failed to execute database script; nested exception is org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: com.mysql.jdbc.Driver
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1512)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:296)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:293)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:628)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4939)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
Caused by: org.springframework.dao.DataAccessResourceFailureException: Failed to execute database script; nested exception is org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: com.mysql.jdbc.Driver
    at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:56)
    at org.springframework.jdbc.datasource.init.DataSourceInitializer.afterPropertiesSet(DataSourceInitializer.java:83)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1571)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1509)
    ... 22 more
Caused by: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: com.mysql.jdbc.Driver
    at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:80)
    at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:45)
    ... 25 more
Caused by: java.sql.SQLException: com.mysql.jdbc.Driver
    at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:254)
    at org.apache.tomcat.jdbc.pool.PooledConnection.connect(PooledConnection.java:182)
    at org.apache.tomcat.jdbc.pool.ConnectionPool.createConnection(ConnectionPool.java:702)
    at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:634)
    at org.apache.tomcat.jdbc.pool.ConnectionPool.init(ConnectionPool.java:488)
    at org.apache.tomcat.jdbc.pool.ConnectionPool.<init>(ConnectionPool.java:144)
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.pCreatePool(DataSourceProxy.java:116)
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.createPool(DataSourceProxy.java:103)
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:127)
    at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111)
    at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77)
    ... 26 more
Caused by: java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1714)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1559)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:247)
    at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:246)
    ... 36 more
Nov 28, 2013 1:51:31 PM org.apache.catalina.core.StandardContext startInternal
SEVERE: Error listenerStart
ERROR ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.jdbc.datasource.init.DataSourceInitializer#0': Invocation of init method failed; nested exception is org.springframework.dao.DataAccessResourceFailureException: Failed to execute database script; nested exception is org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: com.mysql.jdbc.Driver
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1512) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:296) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:293) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:628) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932) ~[spring-context-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479) ~[spring-context-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389) ~[spring-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294) ~[spring-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112) [spring-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4939) [catalina.jar:7.0.42]
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434) [catalina.jar:7.0.42]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) [catalina.jar:7.0.42]
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559) [catalina.jar:7.0.42]
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549) [catalina.jar:7.0.42]
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) [na:1.6.0_29]
    at java.util.concurrent.FutureTask.run(FutureTask.java:138) [na:1.6.0_29]
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) [na:1.6.0_29]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) [na:1.6.0_29]
    at java.lang.Thread.run(Thread.java:662) [na:1.6.0_29]
Caused by: org.springframework.dao.DataAccessResourceFailureException: Failed to execute database script; nested exception is org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: com.mysql.jdbc.Driver
    at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:56) ~[spring-jdbc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.jdbc.datasource.init.DataSourceInitializer.afterPropertiesSet(DataSourceInitializer.java:83) ~[spring-jdbc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1571) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1509) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    ... 22 common frames omitted
Caused by: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: com.mysql.jdbc.Driver
    at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:80) ~[spring-jdbc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:45) ~[spring-jdbc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    ... 25 common frames omitted
Caused by: java.sql.SQLException: com.mysql.jdbc.Driver
    at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:254) ~[tomcat-jdbc-7.0.42.jar:na]
    at org.apache.tomcat.jdbc.pool.PooledConnection.connect(PooledConnection.java:182) ~[tomcat-jdbc-7.0.42.jar:na]
    at org.apache.tomcat.jdbc.pool.ConnectionPool.createConnection(ConnectionPool.java:702) ~[tomcat-jdbc-7.0.42.jar:na]
    at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:634) ~[tomcat-jdbc-7.0.42.jar:na]
    at org.apache.tomcat.jdbc.pool.ConnectionPool.init(ConnectionPool.java:488) ~[tomcat-jdbc-7.0.42.jar:na]
    at org.apache.tomcat.jdbc.pool.ConnectionPool.<init>(ConnectionPool.java:144) ~[tomcat-jdbc-7.0.42.jar:na]
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.pCreatePool(DataSourceProxy.java:116) ~[tomcat-jdbc-7.0.42.jar:na]
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.createPool(DataSourceProxy.java:103) ~[tomcat-jdbc-7.0.42.jar:na]
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:127) ~[tomcat-jdbc-7.0.42.jar:na]
    at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111) ~[spring-jdbc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77) ~[spring-jdbc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    ... 26 common frames omitted
Caused by: java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1714) ~[catalina.jar:7.0.42]
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1559) ~[catalina.jar:7.0.42]
    at java.lang.Class.forName0(Native Method) ~[na:1.6.0_29]
    at java.lang.Class.forName(Class.java:247) ~[na:1.6.0_29]
    at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:246) ~[tomcat-jdbc-7.0.42.jar:na]
    ... 36 common frames omitted
Nov 28, 2013 1:51:31 PM org.apache.catalina.core.StandardContext startInternal
SEVERE: Context [/petclinic] startup failed due to previous errors

你在 data-access.properties 文件中注释掉了 HSQL 的设置吗? - Dan
你不需要在data-access.properties中只添加jpa.showSql=true吗? - Frederic Close
@SotiriosDelimanolis 谢谢。我刚刚发布了一个更完整的堆栈跟踪版本。这有助于您看到问题吗? - CodeMed
是的,ClassNotFoundException 总是表示应用程序的类路径上没有该类。假设您正在使用 Maven,则需要为 MySQL 驱动程序添加依赖项。如果您没有使用 Maven,则需要下载 MySQL 驱动程序 jar 并将其放置在 WEB-INF/lib 中。 - Sotirios Delimanolis
@SotiriosDelimanolis 谢谢。我刚刚进入pom.xml文件,找到了petclinic作者注释掉所需依赖的地方。我取消了注释,然后注释掉了hsql依赖项,更新了项目的maven,关闭了tomcat,然后使用run as...run on server进行清理启动。现在它可以正常工作了。谢谢。如果您将其放在下面的答案中,我会将其标记为答案。 - CodeMed
显示剩余3条评论
3个回答

5

原始错误请参见丹尼尔的答案。当Spring发现无法解析的属性时,它会立即失败,因此直到修复了这个问题之前,它才不会继续查找下一个问题。

对于ClassNotFoundException,答案总是缺少类路径中的类。在这种情况下,您缺少您指定为JDBC驱动程序类的com.mysql.jdbc.Driver

假设您使用的是Maven,您将需要添加MySQL驱动程序的依赖项。如果您没有使用Maven,则需要下载MySQL驱动程序JAR文件并将其放置在Web应用程序的WEB-INF/lib目录中。


谢谢。+1。我能够如此快速地找到并更改pom.xml,是因为你在其他帖子中教给我的东西。非常感谢您对这个网站的贡献。感恩节快乐。 - CodeMed
@CodeMed 只是想告诉你,我没有忽略你。我已经看了你的问题,只是并不总是有答案。 - Sotirios Delimanolis
谢谢。我刚刚做了那个,类是存在的。我在我的应用程序中进行了一些无关的更改。现在,当我使用Eclipse运行“作为..服务器上的运行”时,应用程序无法在Tomcat中加载,并且根错误原因是找不到一个未被触及的任意类。 - CodeMed
谢谢您考虑我的问题!我已经解决了。问题是由于我复制旧控制器类创建新的控制器类时引起的。根本问题在于,在新的控制器类中,我没有将@SessionAttributes(types = someoldclass.class)替换为@SessionAttributes(types = mynewclass.class)。不知何故,当服务器尝试加载应用程序时,它被两个控制器引用到someoldclass所困惑,并将错误指向一个完全无关的类。但是我使用@SessionAttributes(types = mynewclass.class)来解决了这个错误。 - CodeMed
@CodeMed 很高兴我能帮到你。 - Sotirios Delimanolis
显示剩余4条评论

3
在您的 data-access.properties 文件中添加 jpa.showSql = true(或 false,根据您是否想在控制台中看到该信息而定)。请保留 html 标记。

谢谢你的帮助,+1。但是现在出现了一个新的数据库错误。我在上面对原始帖子进行了描述。你有什么建议吗? - CodeMed
我在对Petclinic应用程序进行后续修改时遇到了问题。你有一点时间帮我解决吗?这是另一个问题的链接:http://stackoverflow.com/questions/20292152/parameterizing-object-properties - CodeMed

2

我知道有点晚了,但是我也遇到了Spring的“宠物诊所”示例项目的这个问题,并找到了解决方法。

为了使项目与MySQL一起工作,请按照以下步骤操作:

1-在pom.xml文件中取消注释196-200行(这是启用MySQL驱动程序的方式)

<!-- For MySql only -->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>${mysql-driver.version}</version>
</dependency>

2 - 在data-acccess.properties文件中,将第8-9行更改为以下内容:

jdbc.initLocation=classpath:db/mysql/initDB.sql 
jdbc.dataLocation=classpath:db/mysql/populateDB.sql

...然后注释掉16-22行的代码

...并取消注释28-34行的代码(不包括第33行)

就这样!


感谢您花时间为这个老问题提供见解并点赞。顺便说一下,您可能更好地学习Spring Boot和AngularJS,而不是旧的Petclinic,因为旧的Petclinic使用的是不太现代的技术JSP。虽然有一个Petclinic的AngularJS分支,但它只是一个中级示例。初学者可以通过使用Spring Boot教程从头开始构建,然后使用从GitHub找到的前端内容添加到其中,这些内容可以通过在Google上搜索Spring Boot AngularJS GitHub来找到。 - CodeMed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接