Java standard version of EJB persistence (2)

Source: Internet
Author: User
In the previous article of this tutorial, we talked about using ejb3 persistence-now also known as Java persistence API (JPA)-to maintain the basic knowledge of objects. We use hibernate's entitymanager/Annotations to keep simple person and address classes in the embedded HSQLDB. But there is a one-way relationship between the two classes of person and address: one person points to one address, so let's take a look at how to implement bidirectional ing. In address, we are going to add a series of people -- residents (residents) living in this address ):
public class Address {
...
private Set<Person> residents=new HashSet<Person>(); 
...
}
Now an address may point to multiple persons, so we add a @ onetoworkflow annotation to access the methods corresponding to these residents:
@OneToMany
public Set<Person> getResidents() {
return residents;
public void setResidents(Set<Person> residents) {
this.residents = residents;
} 
When we set an address for a person, in order to maintain the relationship between them, we need to acquire these residents and add each individual to the set. Unless you want to access multiple residents of an address through the sample code in the previous article, just like the following ......
Person p=new Person();
p.setName("John Doe");
p.setAddress(address);
savePerson(p);
address.getResidents().add(p);
-- Otherwise, you will encounter a lazy initialisation error even before you want to keep the changes. When you retrieve an address object, the collection is not retrieved; when you actually access this field, they will be retrieved.
This is to suspend initialization. However, initialization will be suspended only when the object has not been split from the entitymanager. With the code in the previous article, we ignore the separated objects, because we have created and disabled each data access method.
Entitymanager. Now, you can change the residents annotation to achieve this goal ......
@OneToMany(fetch=FetchType.EAGER)
public Set<Person> getResidents() {… 
...... However, this forces the persistence layer to always obtain all relevant data when the object is retrieved. In general, we do not recommend this: over-using it will cause a large number of object trees to be put into memory. You can use
The fetch keyword of ejbql is used for this purpose. We can change the findbypostcode query and add "left join fetch address. Residents" to force the residents attribute to be loaded, as shown below:
Query q=em.createQuery("select address from Address as addressleft join fetch address.residents where postcode=:param "); 
The collection is generally suspended for retrieval, and most other fields are immediately retrieved. This is why when we retrieve a person, its address attribute contains an address object.
Even if we make these changes, there is another problem; we will encounter a transient object exception from person. This is because our saveperson method has no control over the person assigned to it, even if it comes through entitymanagermerge ()
Keep it. When a newly created instance is given, merge () creates a new controlled object and copies the data to this new controlled object.
This is the object lifecycle: When you create a brand new object, it is in a new/Instantaneous State; when you keep it, it is controlled when you keep entitymanager; When entitymanager is disabled, the instance is
Separated. You can re-attach the instance to another entitymanager by means of merging, or use the find method of entitymanager to obtain a new version by detaching the Object ID. There is also a status-delete, that is, when the object is removed from entitymanager
. Now, you may wonder why these different States exist? Well, with them, there is no need to have data transmission objects (DTO) and those specially used to move the returned data to a higher level of the application.
. In this way, only the persistence classes can be separated without data transmission objects and persistence classes.
Back to the sample code, we can change saveperson () to use persist () and add a non-distinct method (not dissimilar method) updateperson (), which uses merge and updateaddress () for address.
Now we can complete the Address Allocation code:
Person p=new Person();
p.setName("John Doe");
p.setAddress(address);
savePerson(p);
address.getResidents().add(p);
updateAddress(address); 
After deleting or adding a person from the residents of each address, you can use updateaddress () to move a person from one address to another address. But moving should be an atomic operation, so we need to implement a moveTo side
Method. Let's start with the premise of "getting entitymanager and transaction:
private void moveTo(Person p,Address a){
EntityManager em=emf.createEntityManager();
EntityTransaction tx=em.getTransaction();
tx.begin(); 
What we need to do is to use the find method of entitymanager to obtain the controllable version of the object;
Person managedperson=em.find(Person.class,p.getId());
Address managedaddress=em.find(Address.class,a.getId()); 
When retrieving controllable instances in a transaction, the content we retrieve from the transaction is also controllable, so we can get a controllable version of the current address:
Address managedoldaddress=managedperson.getAddress(); 
Now, the controllable versions are available, so we can control them as follows:
managedoldaddress.getResidents().remove(managedperson);
managedaddress.getResidents().add(managedperson);
managedperson.setAddress(a); 
Now we must make these changes. Since we only control the controllable version, what we need to do is to make the transaction to maintain the change, where it is from the current entitymanager and transaction:
tx.commit();em.close();} 
Now let's take a look at the tables created in the database. As you expected, there are tables of person and address. You may not have expected another address_person table, which is generated to map the residents' set, resident_id, and address_id.
Field. All these tables and field names are derived from class names. When declaring an object, you can replace it with the @ table annotation, for example;
@Entity@Table(name="Location")public class Address{ 
This code will keep the Address class in a table named location. If you look at the fields generated in the database, you will find that the names of Data columns all come from the attribute names of the class. Similarly, you can use the @ column annotation to replace the field name.
If it is in the Address class, you can insert
@Column(name="postalcode")
public String getPostcode() { return postcode; } 
The postcode attribute will be kept in a data column called postalcode. We can also use @ columnal to set other database attributes of the field, including uniqueness, length, and accuracy of the real database data column. When it works
(Even if it depends on the default name) when the generated data column name does not match the SQL Keyword: for example, we have a field called "select, then you will encounter an error, because the database will reject SQL statements in incorrect format, so the data
Replace the column name with "my_select" to solve this problem.
Now let's go back to the previously generated address_person table. We can add a mappedby parameter to the @ onetoworkflow annotation in the address to delete the table, as shown below:
@OneToMany(mappedBy="address")public Set<Person> getResidents() { 
This is to tell the persistence layer to use the address field of person to map the resident set, and do not generate the address_person table. The Relationship Between Address and person has been enhanced. With this ing, we can use the address attribute set
Keep person. When retrieving the address, we select the person ing of the relevant person record to fill in its resident set. Of course, you may not want to see the close relationship between two entities.
Now there is more ing functions in quickexample, so let's go to another different topic. The advantage of ejb3/JPA is that we can easily move to a different persistence library. To do this, let's modify the previous
To use the glassfish reference implementation of ejb3/JPA.
Theoretically, we only need to modify the persistence. xml file to use glassfish, as shown below:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence">
 <persistence-unit name="example">
  <provider>
   oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider
  </provider>
  <class>quick.Person</class>
  <class>quick.Address</class>
  <properties>
   <property name="jdbc.driver" value="org.hsqldb.jdbcDriver" />
   <property name="jdbc.connection.string"
    value="jdbc:hsqldb:data/example" />
   <property name="toplink.platform.class.name"
    value="oracle.toplink.essentials.platform.database.HSQLPlatform" />
   <property name="jdbc.user" value="sa" />
   <property name="jdbc.password" value="" />
   <property name="ddl-generation" value="dropandcreate" />
   <property name="toplink.logging.level" value="FINE" />
  </properties>
 </persistence-unit>
</persistence>
 
The provider is changed to the toplink version, and the attribute is changed to the toplink variable used for the driver, connection, user name, and password. The dialect attribute of Hibernate is replaced by the "toplink. plafrom. Class. Name" attribute, while "DDL-generation" is
Replace "hbm2ddl" of hibernate. auto "attribute," toplink. logging. the Level Attribute is set to "fine" and replaces the "showsql" attribute of hibernate, while the SQL statement is recorded as part of a common record.
For the build library, we deleted all hibernate libraries and replaced them with libraries from glassfish; anlr. jar, ASM. jar, asm-attrs.jar, javaee. jar and toplink-essentials.jar can be found under the lib directory of glassfish
To. You can download and install it from the glassfish website. Since we can only use libraries from glassfish, we do not need to run the glassfish application server. However, you still need to make adjustments when running the Code. This is a unique requirement of toplink.
Please -- You need to inject proxy, you need toplink-essentials-agent.jar, and at runtime, you need to run the "-javaagent: {path to the jar}/toplink-essentials-agent.jar "added as Java
Virtual Machine parameters.
Now you should be ready to run. As in the past, because we are still in the stage of determining standards, there may be some differences between toplink and hibernate entitymanager/annotations. In the example code of glassfish
Now we have made the following changes.
We added @ joincolumn ("address_id") to the person. Address annotation to solve the significant problem that toplink cannot correctly handle by default. We have to use @ column (name = "address_id") and @ column (name = "person_id ")
Specify the ID attribute of address and person. Otherwise, toplink will call the two "IDS" at the same time and create a strange "ID" data column table for the address_person table, no error or warning prompt is displayed.
We also need to modify the "findby" method so that they are more specific in the where statement reference: for example, "where person. name =: Param "instead of" Where name =: Param ", because toplink is more picky about naming.
Finally, we must use "for (person Pi: ax. getresidents () system. out. println (PI); "replaces" system. out. println (ax. getresidents ())". This is because the toplink's pause loading implementation has
A tostring method does not print the set content, so we must iterate in the set. With this change, we can run the sample code.
To really run the code, we need to change the underlying database from the embedded hsql to the MySQL server. We will assume that you have set up the MySQL server, downloaded the MySQL JDBC drive, and added it to your library. In this case, what we need to do is
Is to change the attributes in persistence. xml:
…<property name="jdbc.driver" value="org.gjt.mm.mysql.Driver"/>
<property name="jdbc.connection.string"value="jdbc:mysql://localhost:3306/example"/>
<property name="toplink.platform.class.name"value="oracle.toplink.essentials.platform.database.MySQL4Platform"/>
<property name="jdbc.user" value="root"/><property name="jdbc.password" value=""/>… 
We told the persistence layer to use the MySQL JDBC driver and use the class of mysql4platform from toplink. The setting here is a local MySQL server with a root account without a password; you should replace the user name and password as needed. With Me
It is worth noting that the latency after running data can be solved. There is no need to worry that the embedded database will lose data when the External SQL Server takes over. As you can see, you can choose which database to use in the deployment phase.
For the purpose of comparison, the entitymanager/Annotations of hibernate uses the following MySQL attributes:
<property name="hibernate.connection.driver_class"value="org.gjt.mm.mysql.Driver"/>
<property name="hibernate.connection.url"value="jdbc:mysql://localhost:3306/example"/>
<property name="hibernate.dialect"value="org.hibernate.dialect.MySQLDialectDialect"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.password" value=""/>
This month, we discussed more annotations and mappings between available entities in ejb3/JPA, extended the example to glassfish/toplink, and switched the database. Next month, we will study how to make it easier to keep objects and show you how to use ejb3/JPA.
To test the enterprise class, instead of calling the entire framework in a single test.
 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.