This is a simple guide for configuring JPA and connecting to your database using JTA transaction mode. Also it is including the most common mistakes that developers do and you should avoid them.
Hope this help you.
1- Set up a DataSource in your Application Server:
In order to configure JPA in your WebApp using JTA mode you need 1st setting up a DataSource. You can setup the DataSource from your Application Server (Glassfish / Payara / ...). but it is recommended to setup the Datasource through your Web App. Follow these steps to setup the DataSource for Glassfish or Payara through your Maven WebApp:
create a new folder (NOT Package) inside your project folder with name "setup".
create a new xml file and name it "glassfish-resources.xml" and save it inside "setup" folder.And write the bellow content:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
<jdbc-resource enabled="true" jndi-name="**jdbc/DBDev01**" object-type="user" pool-name="**jdbc/DBDev01-ConnectionPool**">
<description/>
</jdbc-resource>
<jdbc-connection-pool allow-non-component-callers="false"
associate-with-thread="false" connection-creation-retry-attempts="0"
connection-creation-retry-interval-in-seconds="10"
connection-leak-reclaim="false"
connection-leak-timeout-in-seconds="0"
connection-validation-method="auto-commit"
datasource-classname="**org.mariadb.jdbc.MariaDbDataSource**"
fail-all-connections="false"
idle-timeout-in-seconds="300"
is-connection-validation-required="false"
is-isolation-level-guaranteed="true"
lazy-connection-association="false"
lazy-connection-enlistment="false"
match-connections="false"
max-connection-usage-count="0"
max-pool-size="32"
max-wait-time-in-millis="60000"
name="**jdbc/DBDev01-ConnectionPool**"
non-transactional-connections="false"
pool-resize-quantity="2"
res-type="javax.sql.DataSource" statement-timeout-in-seconds="-1" steady-pool-size="8" validate-atmost-once-period-in-seconds="0" wrap-jdbc-objects="false">
<!-- for MariaDB users, it recomended to add ?useMysqlMetadata=true, this will make MariaDB pretending that it is a MySQL for tools or libraries that not support MariaDB -->
<property name="URL" value="**jdbc:mariadb://XXX.XXX.XXX.XXX:XXXX/DB_NAME?useMysqlMetadata=true**"/>
<property name="User" value="**USERNAME**"/>
<property name="Password" value="**PASSWORD**"/>
</jdbc-connection-pool>
</resources>
Note: All values in between ** ** should be modified as per your settings.
This file will be loaded by your application server (Glassfish/Payara) after deploying your webapp. For Payara users you can also name the file with "payara-resources.xml" but with little modifications. Ref:Payara Deployment Descriptors.
2- Add Resource reference for the datasource in WEB-INF/web.xml:
you need to add a resource reference for the DataSource in your Webapp through adding this in WEB-INF/web.xml file:
<web-app .....>
......
<resource-ref>
<description>**DBDev01**</description>
<res-ref-name>**jdbc/DBDev01**</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<!-- <res-sharing-scope>Shareable</res-sharing-scope> -->
</resource-ref>
</web-app>
Note: The res-ref-name should match exactly the name you choose for the datasource in glassfish resources file.
3- Configure Persistence.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="**MyDB**" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<!-- List all Entity classes -->
<class>**com.MyEntityClassName**</class>
<jta-data-source>**jdbc/DBDev01**</jta-data-source>
<!-- you can list all entity classes you need and set this value to true. or set this value to false to include other entity clases -->
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<!-- while eclipselink not support MariaDB , set this property to enforce eclipselink to work with it as MySQL -->
<property name="eclipselink.target-database" value="MySQL"/>
</properties>
</persistence-unit>
</persistence>
Note 1: If you want to use JTA as transaction type, So you must defining jta-data-source. And it is a common mistake for developers adding DB URL,username and password in properties trying to connect to the database without defining the JTA data Source. This will not work and will lead your application server to use the default datasource that already defined which in common is an H2 database.
Note 2: eclipselink (JPA library) not supporting MariaDB. But there is a workarounds for that.
solution 1:: add "?useMysqlMetadata=true" as suffix on your connection URL Like: <property name="URL" value="**jdbc:mariadb://XXX.XXX.XXX.XXX:XXXX/DB_NAME?useMysqlMetadata=true"/> this will make MariaDB pretending that it is a MySQL.
solution 2: Enforce eclipselink to deal with the database as MySQL. this can be done by setting eclipselink.target-database property in persistence.xml as bellow:
<properties>
<!-- while eclipselink not support MariaDB , set this property to enforce eclipselink to work with it as MySQL -->
<property name="eclipselink.target-database" value="MySQL"/>
</properties>
4- Add JDBC client as Dependency in POM.xml:
<dependency>
<!-- This is for MariaDB. You should change it if you are using other kind of DB like MySQL or Oracle DB -->
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>2.7.2</version>
</dependency>
5- Enjoy with your Codes:
writing a sessionBean:
#Stateless
public class StudentManager
{
/* Notes:
1.you should use the same name exactly that defined in Persistence.xml file.
2.You can not use #PersistenceUnit with JTA. only use #PersistenceContext with JTA.
*/
#PersistenceContext(unitName="MyDB")
private EntityManager em;
public StudentManager()
{
}
public void persist(Student student) {
em.persist(student);
}
}
write TestController:
#Named
#SessionScoped
public class TestController
{
#Inject
private StudentManager studentManager;
private String message = "";
public void test()
{
Student student = new Student();
Student.setCode(11223344);
Student.setName("John");
studentManager.persist(Student);
/*Note:we used studentManager directly without constructing.
writing studentManager = new StudentManager() is a common mistake and will lead you to get a null EntityManager.*/
this.setMessage("A new Student already saved successful with Code:" + Student.getCode());
}
Common Question: Should use #Inject or #EJB? here is the answer
A simple JSF page for testing:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
<h:form>
<h:commandButton value="Test Save a Student over JTA" action="#{testController.test()}" />
<br />
<h:outputLabel for="message" value="#{test.message}" />
</h:form>
</h:body>
</html>
Related
I am working on a project where I am using play framework along with mongo db. As of now I have hardcoded the value for local db connection in persistence.xml file and given the jpa.default value as persistenceUnitName and I am using the play's JpaApi for the db operations (which inherently uses the entity manager).
I am not able to identify how to define environment (prod, dev, stage) specific db properties like host, url etc. in application.conf or any other file.
application.conf entry - jpa.default=my-local-jpa
<?xml version="1.0" encoding="UTF-8"?>
<persistence
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
<persistence-unit name="my-local-jpa" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider>
<non-jta-data-source>DefaultDS</non-jta-data-source>
<properties>
<property name="hibernate.ogm.datastore.provider"
value="org.hibernate.ogm.datastore.mongodb.impl.MongoDBDatastoreProvider"/>
<property name="hibernate.ogm.datastore.host"
value="127.0.0.1"/>
<property name="hibernate.ogm.datastore.port" value="27017"/>
<property name="hibernate.ogm.datastore.database" value="my_db"/>
<property name="hibernate.ogm.datastore.safe" value="true"/>
<property name="hibernate.ogm.datastore.create_database" value="true" />
</properties>
</persistence-unit>
</persistence>
There would be different solutions. It depends on your environment.
If you are using WildFly / JEE container, you can configure a WildFly NoSQL subsystem, providing there the references to the remote datastore. It would be the equivalent of a SQL datasource, but for a NoSQL datastore. See Using WildFly NoSQL
If you are using a web container, there would be different strategies.
You can create different war(s), one for each environment, for instance using maven profiles.
Alternatively, you can configure your Spring context in order to use an external property file. See this question.
If you deploy it in a PASS, such as OpenShift, you can mount the persistence.xml file as a config map. See Config Map - OpenShift doc
I have read some of the answers like by appending ?searchpath=myschema or ?currentSchema=myschema but it still doesn't work in my case. I use NetBeans and I can execute commands to the connection with the intended schema and it works well but in run time, Glassfish only connects to public schema ignoring the ?currentSchema=myschema. My postgresql version is 9.6 and the JDBC driver version is the latest 42.0.0
This is my glassfish-resource.xml:
<resources>
<jdbc-connection-pool allow-non-component-callers="false" associate-with-thread="false" connection-creation-retry-attempts="0" connection-creation-retry-interval-in-seconds="10" connection-leak-reclaim="false" connection-leak-timeout-in-seconds="0" connection-validation-method="auto-commit" datasource-classname="org.postgresql.ds.PGSimpleDataSource" fail-all-connections="false" idle-timeout-in-seconds="300" is-connection-validation-required="false" is-isolation-level-guaranteed="true" lazy-connection-association="false" lazy-connection-enlistment="false" match-connections="false" max-connection-usage-count="0" max-pool-size="32" max-wait-time-in-millis="60000" name="post-gre-sql_aegwyncreds_dbexerphi_dbaPool" non-transactional-connections="false" pool-resize-quantity="2" res-type="javax.sql.DataSource" statement-timeout-in-seconds="-1" steady-pool-size="8" validate-atmost-once-period-in-seconds="0" wrap-jdbc-objects="false">
<property name="serverName" value="localhost"/>
<property name="portNumber" value="5432"/>
<property name="databaseName" value="mydb"/>
<property name="User" value="user"/>
<property name="Password" value="pass"/>
<property name="URL" value="jdbc:postgresql://localhost:5432/mydb?currentSchema=myschema"/>
<property name="driverClass" value="org.postgresql.Driver"/>
</jdbc-connection-pool>
<jdbc-resource enabled="true" jndi-name="java:app/myjndisource" object-type="user" pool-name="post-gre-sql_mydb_user_dbaPool"/>
</resources>
This is my persistence unit:
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="myPU" transaction-type="JTA">
<jta-data-source>java:app/myjndisource</jta-data-source>
<class>myclass</class>
. . . . . . . . . .
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
</properties>
</persistence-unit>
</persistence>
I finally figured it out by myself after combining some Google results, I hope that this useful for people who are like me. Here are some conclusions that I made.
Adding the currentSchema=myschema in jdbc-conncetion-pool element doesn't change anything in JPA if that connection is used in JPA and specified in the persistence unit, like my previous example:
java:app/myjndisource
EntityManager still uses public schema and ignore the specified schema.
We need to use orm.xml file to specify the schema that we want, like in this example:
JPA - EclipseLink - How to change default schema
The orm.xml file can be set with any name but it must be on the classpath. In NetBeans you can use this folder structure as example since you can't generate this file with Netbeans built in help.
Web Pages -> WEB-INF -> classes -> META-INF -> ( the mapping files )
Netbeans web application structure
Then in the persistence unit we can specify the mapping-file element, but remember these 2 points
A. In Netbeans ( or perhaps other IDES ), you must place the mapping-file element after the jta-data-source element but before class element otherwise there will be some deployment error like in this link:
https://netbeans.org/bugzilla/show_bug.cgi?id=170348
B. If you name the mapping file with the name orm.xml and include it in the same directory with your persistence unit, automatically the persistence unit includes that mapping file although you don't specify it with the mapping-file element.
So if you have 2 mapping files and one of them named orm.xml and both of them include schema element and your persistence unit uses mapping-file element for the other mapping file there will be an error because of the conflicting schema.
I'm developing a first application on openshift. Its a jsf application with database connectitivity.
First i tryed onli some jsf xhtml page without jpa and all works.
When i insert a bean to acces to the database i have the message from the server "failed deployments ./ROOT.waer. Precisely when I insert this code something goes wrong :
A class for view intents
#ManagedBean(name="utnavctrl" ,eager=true)
#SessionScoped
public class Utnavctrl {
boolean newrecord=false;
#EJB
private Usersdao usersdao;
public Utnavctrl(){
A bean class for db connection
#Stateless
#LocalBean
public class Usersdao {
#PersistenceContext(unitName = "primary")
private EntityManager em;
public Usersdao() {
// TODO Auto-generated constructor stub
}
public List<User> getAllUsers() {
return em.createNamedQuery("User.findAll", User.class)
.getResultList();
}
I can't understand why after adding these two class (without modifing the view side xhtml ecc) the program doesn't work anymore.
The persince.xml is
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="primary">
<!-- If you are running in a production environment, add a managed
data source, this example data source is just for development and testing! -->
<!-- The datasource is deployed as WEB-INF/kitchensink-quickstart-ds.xml, you
can find it in the source at src/main/webapp/WEB-INF/kitchensink-quickstart-ds.xml -->
<jta-data-source>java:jboss/datasources/MySQLDS</jta-data-source>
<class>com.antoiovi.gestcars.model.Automobili</class>
<class>com.antoiovi.gestcars.model.Group</class>
<class>com.antoiovi.gestcars.model.Prenotazioniauto</class>
<class>com.antoiovi.gestcars.model.Proglav</class>
<class>com.antoiovi.gestcars.model.Role</class>
<class>com.antoiovi.gestcars.model.User</class>
<class>com.antoiovi.gestcars.model.UserData</class>
<properties>
<!-- Properties for Hibernate -->
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="hibernate.show_sql" value="false" />
</properties>
</persistence-unit>
</persistence>
Thhe bean.xml is
<?xml version="1.0" encoding="UTF-8"?>
<!-- This file can be an empty text file (0 bytes) -->
<!-- We're declaring the schema to save you time if you do have to configure
this in the future -->
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</bean
Can anybody help me?
Remove eager=true because this creates problems with OpenShift...I do not know why but I have seen.
I'm nearly new to JavaEE (JRE7/JDK1.7.0) and startet my first (maven based) Project on Eclipse (Luna).
Applicationserver is JBoss EAP 6.2.0.GA (AS 7.3.0.Final-redhat-14) which I updated to JSF2.2 by adding jsf-api-2.2.7.jar and jsf-impl-2.2.7.jar and registering in module.xml - which works perfect, by the way.
The problem/question is, why can't I get the EntityManager from the container (AS) with Injection, with following code in my Project:
#Stateless
public class SCatRep {
#PersistenceContext
EntityManager em;
private ...
*In persistence.xml there is only one persistenceunit defined. So no further arguments are necessary ... in my opinion?!
On the other hand, when I try to get the EntityManager from container with a lookup, the EntityManager is present and everything works fine. I used this code (for testing):
#Stateless
#PersistenceContext(unitName="scha", name="persistence/em")
public class SCatRep {
EntityManager em;
public SCatRep() {
try {
Context ic = new InitialContext();
em = (EntityManager) ic.lookup("java:comp/env/persistence/em");
} catch (NamingException e) {
e.printStackTrace();
}
}
I read a lot forums and tutorials - because this behaviour is discussed a lot - but can't get a solution or answer. Hope somebody can help me and point me to the right direction.
Thanks in advance.
EDIT:
I'm using EJB 3.1. And here is the persistence.xml:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="scha" transaction-type="JTA">
<jta-data-source>java:/scha_jndi</jta-data-source>
<properties>
<!-- SQL dialect -->
<property name="dialect" value="org.hibernate.dialect.MySQLDialect" />
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class" value="thread" />
<!-- Echo all executed SQL to stdout -->
<property name="show_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
Thanks for help.
I tried to access the EntityManager in constructor ... which is not possible, due to the initializationprocess.
Now I put the Initial loading (databaseaccess) in a #PostConstruct-annotated method and this works perfectly.
everybody!
I've been trying to find the answer for some time but I didn't manage.
I try to configure my application and make it work under JBoss Application Server 7.1.1, using Enterprise Java Beans. My application is Web application, it uses servlets and injects other classes as EJBs. The problem is that every statement gets commited, so that means no transaction management is supported.
In my test example I have an entity with a collection of children (mapped with a relationship OneToMany with a property CascadeType.ALL). If a record in a collection has some problems (e.g. non-existing foreign key), it can't be inserted into table and throws exception. However, the parent entity gets inserted, so I assume the inserts are done in different separate transactions. This is strictly undesired behavior and I try to resolve it.
Technical parameters:
DBMS: Oracle EE 11g
AS: JBoss AS 7.1.1
my persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/">
<persistence-unit name="OracleEntityManager">
<jta-data-source>java:jboss/CmaDevDS</jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle9iDialect" />
<property name="hibernate.hbm2ddl.auto" value="none" />
<property name="hibernate.jdbc.batch_size" value="20" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.use_sql_comments" value="true" />
</properties>
</persistence-unit>
</persistence>
my EJB:
#Stateless(name="EntityWriter")
#TransactionManagement(TransactionManagementType.CONTAINER)
public class EntityWriter {
#Resource
private SessionContext context;
/*#Resource
UserTransaction ut;*/
#PersistenceContext(unitName = "OracleEntityManager",type=PersistenceContextType.EXTENDED)
EntityManager em;
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public EntityMarker insertEntity(EntityMarker entity)throws Exception
{
try
{
entity = em.merge(entity);
em.flush();
return entity;
}
catch (Exception e)
{
context.setRollbackOnly();
e.printStackTrace();
return null;
}
}
}
Actually I tried both EJB approaches: Container Management Transaction and Bean Management Transaction and neither works as I expect.
When I inject the bean into servlets I do it like this:
#EJB(name = "EntityWriter")
private EntityWriter entityWriter;
Now I think the bean is fine, probably something is missing in persistence.xml.
Would be grateful to any ideas. Thanks in advance!
Everything works correct after I edited Datasource configuration via JBoss Administration console and set a checkbox "Use JTA". It was unchecked by default.
You're right, Chris. Thanks!