Почему JBoss не может найти драйвер MySQL под Hibernate + JPA

У меня есть три проекта: Web, EJB3, JPA-сущности. Проект EJB3 и JPA-entity будет экспортирован в Web/WebContent/WEB-INF/lib в виде jar-файлов. Я также поместил файл jar драйвера MySQL в "WEB-INF/lib".

но...

jboss не может найти драйвер MySQL... следующий файл persistence.xml:

<persistence-unit name="HandShakeEntity">
        <class>net.magidea.handshake.entity.User</class>
        <class>net.magidea.handshake.entity.UserItem</class>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
            <property name="hibernate.connection.username" value="root" />
            <property name="hibernate.connection.password" value="dj/4ej03" />
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/handshake" />
            <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
        </properties>
    </persistence-unit>

и войти:

13:09:26,070 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 48) MSC000001: Failed to start service jboss.persistenceunit."HandShakeWeb.war#HandShakeEntity": org.jboss.msc.service.StartException in service jboss.persistenceunit."HandShakeWeb.war#HandShakeEntity": javax.persistence.PersistenceException: [PersistenceUnit: HandShakeEntity] Unable to build EntityManagerFactory
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1.run(PersistenceUnitServiceImpl.java:103) [jboss-as-jpa-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) [rt.jar:1.7.0_07]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) [rt.jar:1.7.0_07]
    at java.lang.Thread.run(Thread.java:722) [rt.jar:1.7.0_07]
    at org.jboss.threads.JBossThread.run(JBossThread.java:122) [jboss-threads-2.1.0.Final-redhat-1.jar:2.1.0.Final-redhat-1]
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: HandShakeEntity] Unable to build EntityManagerFactory
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:930)
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:904)
    at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:92)
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.createContainerEntityManagerFactory(PersistenceUnitServiceImpl.java:200) [jboss-as-jpa-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8]
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.access$600(PersistenceUnitServiceImpl.java:57) [jboss-as-jpa-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8]
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1.run(PersistenceUnitServiceImpl.java:99) [jboss-as-jpa-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8]
    ... 4 more
Caused by: org.hibernate.service.classloading.spi.ClassLoadingException: Specified JDBC Driver com.mysql.jdbc.Driver could not be loaded
    at org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl.configure(DriverManagerConnectionProviderImpl.java:111)
    at org.hibernate.service.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:75)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:159)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:131)
    at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.buildJdbcConnectionAccess(JdbcServicesImpl.java:223)
    at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:89)
    at org.hibernate.service.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:75)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:159)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:131)
    at org.hibernate.cfg.SettingsFactory.buildSettings(SettingsFactory.java:78)
    at org.hibernate.cfg.Configuration.buildSettingsInternal(Configuration.java:2283)
    at org.hibernate.cfg.Configuration.buildSettings(Configuration.java:2279)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1748)
    at org.hibernate.ejb.EntityManagerFactoryImpl.<init>(EntityManagerFactoryImpl.java:94)
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:920)
    ... 9 more
Caused by: org.hibernate.service.classloading.spi.ClassLoadingException: Unable to load class [com.mysql.jdbc.Driver]
    at org.hibernate.service.classloading.internal.ClassLoaderServiceImpl.classForName(ClassLoaderServiceImpl.java:149)
    at org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl.configure(DriverManagerConnectionProviderImpl.java:106)
    ... 23 more
Caused by: java.lang.ClassNotFoundException: Could not load requested class : com.mysql.jdbc.Driver
    at org.hibernate.service.classloading.internal.ClassLoaderServiceImpl$AggregatedClassLoader.findClass(ClassLoaderServiceImpl.java:296)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423) [rt.jar:1.7.0_07]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356) [rt.jar:1.7.0_07]
    at java.lang.Class.forName0(Native Method) [rt.jar:1.7.0_07]
    at java.lang.Class.forName(Class.java:264) [rt.jar:1.7.0_07]
    at org.hibernate.service.classloading.internal.ClassLoaderServiceImpl.classForName(ClassLoaderServiceImpl.java:146)
    ... 24 more

Есть решение, которое я нашел неожиданно. Если я помещаю jar драйвера MySQL в [JBoss EAP 6.1 Home]\modules\system\layer \base\org\hibernate\main и обновляю module.xml, чтобы включить jar драйвера, это работает, но я не знаю, почему мой Web Приложение связано с модулем гибернации.

1 ответ

Решение

Это из-за того, как загрузка классов работает в среде JEE. Видите ли, есть вложенные загрузчики классов, а загрузчик классов веб-приложения идет в конце иерархии. Это означает, что в то время как загрузчик классов веб-приложения может видеть классы, загруженные его родителями, его родители не могут видеть классы, загруженные дочерним элементом (CL веб-приложения).

В среде JEE у вас есть системный загрузчик классов (как всегда), тогда будет загрузчик классов сервера приложений (загружает API - например, javax.servlet.* и конкретные реализации сервера приложений). Наконец, есть загрузчик классов на EAR, затем загрузчик классов на WAR, как:

system CL
|
+- Application server CL (loads e.g. Hibernate as the JPA implementation)
   |
   +- EAR 1 CL
   |  |
   |  +- WAR 1_1 CL
   |  |
   |  +- WAR 1_2 CL
   |
   +- WAR 1 CL (In your case, this loads the MySQL driver)

(это упрощено, просто для демонстрации принципов) Каждый дочерний элемент в дереве выше видит классы, загруженные его родителями, но НЕ классы, загружаемые его собственными дочерними элементами или пирами.

В вашем случае JAR драйвера MySQL находится в WEB-INF/lib то есть загружается CL веб-приложения, но реализация JPA (Hibernate) загружается родительским CL. Этот CL пытается найти классы для драйвера и терпит неудачу по причине, описанной выше. Это также, почему все работает, когда вы помещаете драйвер в modules/, поскольку это classpath родительского CL, который загружает Hibernate.


В любом случае я думаю, что решение состоит в том, чтобы поместить драйвер в modules/, как описано в разделе "Установка драйвера JDBC". Если у вас есть веская причина для объединения вещей в вашем приложении, то вам придется также связать реализацию JPA (т.е. поместить JAR-файлы Hibernate в EB-INF/lib тоже).

Другие вопросы по тегам