Showing posts with label Database. Show all posts
Showing posts with label Database. Show all posts

Thursday, November 12, 2015

Understand Glassfish JDBC configuration by inspecting JDBC DataSource API

When configure DataSource on JEE container Glassfish, There are 2 things need to be set, JDBC Resource and JDBC Connection Pools.

image

What's the difference and why are these two items? What's the relation between them? We can answer that by inspecting the Java JDBC API, mainly in package javax.sql

1. How to connect to DB

To work with DB in Java, the application must have a connections  (java.sql.Connection) to the database.  There are 2 ways to get a connection in JDBC:

  • Method 1, using static method, DriverManager.getConnection(url). This is a very old way, still valid, only used in small standalone applications, doesn't support pooling.
  • Method2, using DataSource interface. Recommended. In most case work with JNDI lookup to get one from a container.

2. The hierarchy of DataSource

 

jdbc

There are some points need to be noticed about this diagram:

They are all interfaces. No concrete class at all.

There are 3 interfaces related to data source, DataSource/ConnectionPoolDataSource/XADataSource.

Application Java code will ONLY come into contact with the green part. DataSource and Connection.

ConnectionPoolDataSource instance can create PooledConnection instance(pooled...you know,name tells all), XADataSrouce can create XAConnection (for distributed transaction)

The ConnectionPoolDataSource, although may sounds like, but is not a Child of DataSource. In other words, A  ConnectionPoolDataSource instance can't be simply casted to DataSource instance. So inside a DataSource instance, the real work will somehow be delegate to a ConnectionPoolDataSource/XADataSouce.

Same thing applied to Connection. The Connection has nothing to do with PooledConnection, although they looks similar. No casting but delegation.

Up to know you should understand the relationship between JDBC Resource and JDBC Connection Pools in Glassfish Administration GUI. Think JDBC Resource as DataSource and JDBC Connection Pools  as ConnectionPoolDataSource.

3. Using MySQL in Glassfish

Let's use MySQL's official developer guide on "Using Connector/J with GlashFish" as a testify. On this document, the configuration has 2 steps:

  • step1. Creating a Connection Pool, filling in  information like DB's IP address, username and password for make "real" connections to database.
  • step2. Create a JDBC Resource. choose a pool created in step 1 and set a JNDI name for it.  We can say the JDBC Resource HAS-A pool.

The steps can pretty much demonstrate the hierarchy of DataSource in JDBC API, which once get understood will make the configuration steps make sense and easy to remember.

Friday, October 30, 2015

How to use embedded Java DB (Derby) in maven project

For now, Java DB is actually just Apache Derby with a different name.  In the following of the article, we will call it Derby. It  comes with JDK installation. ( Although what's normally used in maven project is not the same binary install in local JDK directory)

Using embedded Java DB means the database will run in the same JVM as your application. The Java DB engine actually gets started when you try to connect to it by JDBC. When the application exits, the database also exits. If you choose to run the Java DB total in memory, when the JVM stops, the data will be gone. Or you can choose to store the data on local file system to make them usable during multiple runs.

Java DB (Derby) is mostly used for convenience in development. No external database is needed even you have code need to play with RMDB.

0. What you need

  • JDK 6+ (JDK 7 in this demo)
  • Maven 3.2 +

1. POM file

There's only one dependency needed to use Derby database.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.shengwang.demo</groupId>
<artifactId>javadb-derby-embedded-basic</artifactId>
<version>1.0</version>
<packaging>jar</packaging>

<name>javadb-derby-embedded-basic</name>
<url>http://maven.apache.org</url>

<dependencies>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>10.8.3.0</version>
</dependency>
</dependencies>

<!-- Use Java 1.7 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

Since the version of Java DB comes with JDK 7 is 10.8.3.x, we also use 10.8.3.0 in our maven project. If just using in-memory database(see below), the version used in maven actually doesn't matter. But if database file stores on file system and you want to check the database content after application finishes, you'd better use the same version as from JDK, so the 'ij' tool in $JAVA_HOME/db/bin can open the database without version conflicts.


2. When the embedded database starts


The database starts when you java code try to connect to it by using standard JDBC. How the derby work depends on the way to connect to it, or in other words, depends on the connection url. Suppose we need to connect to a database named 'demo'.


In-memory database, url looks like: jdbc:derby:memory:demo;create=true


'demo' is the database name and can be any string you choose, "memory" is a key word to tell Derby  to goes to all-in-memory mode.


File-based database, url looks like: jdbc:derby:c:\Users\shengw\MyDB\demo;create=true


'c:\Users\shengw\MyDB\demo' is the directory to save database files on local file system. (On windows its actually jdbc:derby:c:\\Users\\shengw\\MyDB\\demo;create=true because of the String escaping)


'create=true' is a Derby connection attribute to create the database if it doesn't exist. If use in-memory database, this attribute is mandatory.


3. A complete example


This is a complete hello world level example using embedded Derby database in Maven project. The HelloJavaDb.java lists below.

package com.shengwang.demo;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class HelloJavaDb {
Connection conn;

public static void main(String[] args) throws SQLException {
HelloJavaDb app = new HelloJavaDb();

app.connectionToDerby();
app.normalDbUsage();
}

public void connectionToDerby() throws SQLException {
// -------------------------------------------
// URL format is
// jdbc:derby:<local directory to save data>
// -------------------------------------------
String dbUrl = "jdbc:derby:c:\\Users\\shengw\\MyDB\\demo;create=true";
conn = DriverManager.getConnection(dbUrl);
}

public void normalDbUsage() throws SQLException {
Statement stmt = conn.createStatement();

// drop table
// stmt.executeUpdate("Drop Table users");

// create table
stmt.executeUpdate("Create table users (id int primary key, name varchar(30))");

// insert 2 rows
stmt.executeUpdate("insert into users values (1,'tom')");
stmt.executeUpdate("insert into users values (2,'peter')");

// query
ResultSet rs = stmt.executeQuery("SELECT * FROM users");

// print out query result
while (rs.next()) {
System.out.printf("%d\t%s\n", rs.getInt("id"), rs.getString("name"));
}
}
}

The demo uses derby database, creates a table 'users', inserts 2 rows into the table and prints the query result set.  The whole maven project hierarchy is :


image



After running the HelloJavaDb example, you can verify the database, because we are not using derby in all-in-memory mode.  After running, the database files will appear on local file system like this. 


image


If you connect to the database in command line, you can see the 2 rows add from your Java code. 'ij' is a tool provided by Derby works as a sql client.


image

Thursday, June 11, 2015

Ehcache Issue : Element <cache> does not allow attribute "maxEntriesLocalHeap"

When using Ehcache as Hibernate second level cache provider, You may face the org.xml.sax.SAXException like this:

Caused by: org.xml.sax.SAXException: null:25: Element <cache> does not allow attribute "maxEntriesLocalHeap".

Reason

This is because in “maxEntriesLocalHeap” is used in ehcahe configuration file ehcache.xml. “maxEntriesLocalHeap” is introducted to ehcache from 2.5, so if the actually ehcache-core version in you project is less then 2.5, the excpetion above comes out.

Unfortunately, Hibernate 4.3 release still uses ehcache 2.4.3. So if the project pom.xml just like this, the exception occures.

<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>4.3.4.Final</version>
</dependency>

image


Solution


To solve this, just add explicit dependency to you project.

<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>4.3.4.Final</version>
</dependency>

<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.6.5</version>
</dependency>

Now the dependency looks like this, the SAXException is gone.


image

Tuesday, June 9, 2015

Use JMX to monitor Hibernate 4.3 statistics (with Spring)

To find out hibernate cache’s performance, like cache hit/miss ratio, JMX can be convenient. Before Hibernate 4.3, there is a StatisticsService class can be used. But Hibernate 4.3 removed this class.  If the project also uses Spring framework, it can still be done. 

The original solution came from Marcel Stor from here. This article try to compliment it with details.

0. What you need

  • JDK1.7 +
  • Maven 3.2.1+
  • Spring 4.1.0.RELEASE
  • Hibernate 4.3.4.Final

1. Define Java class

One Jave class is needed. Add the following class to the project.  The class is defined as a normal Spring bean with @Component annotation.

package com.shengwang.demo.statistics;

import org.hibernate.SessionFactory;
import org.hibernate.stat.Statistics;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class HibernateStatisticsFactoryBean implements FactoryBean<Statistics> {

@Autowired
private SessionFactory sessionFactory;

@Override
public Statistics getObject() throws Exception {
return sessionFactory.getStatistics();
}

@Override
public Class<?> getObjectType() {
return Statistics.class;
}

@Override
public boolean isSingleton() {
return true;
}
}

2. Configure Spring


Configure Spring, add following to the spring configuration xml file.

<!-- ==================================== -->
<!-- Hibernate 4.3 Statistics for JMX -->
<!-- ==================================== -->
<bean id="jmxExporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="Hibernate:type=statistics">
<ref bean="hibernateStatisticsFactoryBean"/>
</entry>
</map>
</property>
</bean>

The bean hibernateStatisticsFactoryBean used is the Class defined above. 


All done!


3. Check from JConsole


Run JConsole, the JMX tool shipped with JDK, connect to the running project. Now hibernate statistics can be monitored!


Connect to the Java application process.

image

Now the Hibernate performance can be monitored by JMX, for example the 2nd level cache hit ratio in the following snapshot.


image

Monday, May 18, 2015

Understand all about hibernate fetch - WHEN and HOW

As Hibernate official document says:

Hibernate have two orthogonal notions here: when is the association fetched and how is it fetched.

There are many words on different document to describe ORM fetch like fetch strategy, fetch type, fetch mode, but in essence just the concept of WHEN and HOW.

In this article, a One-To-Many example will be used to demonstrate the concept.  A Client entity and a PurchaseOrder Entity are used in the demo code. One client can have many purchase orders. There are 5 clients in database and every client has 10 orders.

image

0. Environment and version

  • Java 7 (JPA2.0)
  • Hibernate 4.x

The following example and discuss are based on this environment.

1. Concept in short

1.1 WHEN to fetch

  • Eager : Assemble SQL and access database immediately when an entity is created. JPA compatible
  • Lazy  -  A wrapper class called 'proxy' is used for the entity, when an entity is created. The database access only happens when entity's value gets used. JPA compatible. Default behavior. 
  • Extra Lazy  -  Try not to fetch the whole collection into memory unless absolutely needed. Not JPA compatible

When means at what time will hibernate assemble a SQL clause to access the database.

1.2 How to fetch

If a entity have associations, how the associations of the entity get loaded.  In our Client-To-PurchaseOrder(One-To-Many) demo, when a client entity is loaded, how to get his purchase orders. 

  • Join  - Use SQL outer join to get associations. Be careful about the return list, it may not like what you expect,  see the demo below.   JPA compatible. Default behavior for Eager.
  • Select  - Use a separate select to get only 1 entity's association,  will cause the 'N+1' problem.   JPA compatible. Default behavior FOR Lazy.  
  • Batch  -  Use a separate select to get a batch size entities' association. Can be treated as a kind of improvement of 'Select' Not JPA compatible
  • Subselect  -  Use a separate select to get all associations for all entities retrieved in a previous query. Not JPA compatible

JPA compatible means in java code, only classes or annotations from javax.persistence.* are used, no need to import any thing  from  org.hibernate.*.  Hibernate can just be used as persistence provider in JPA configure file persistence.xml, which makes the the application not close coupled with Hibernate.

2. Code for demo

2.1 The Entity definitions

The entity PurchaseOrder is plain. Nothing's tricky here.

package com.shengwang.demo.model;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;


@Entity
@Table(name="purchase_order")
public class PurchaseOrder {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="order_id")
private int orderId;

@Column(name="order_desc")
private String orderDesc;

@ManyToOne(cascade=CascadeType.PERSIST)
@JoinColumn(name="client_id")
private Client client;

public int getOrderId() {
return orderId;
}

public String getOrderDesc() {
return orderDesc;
}


public Client getClient() {
return client;
}

public void setOrderId(int orderId) {
this.orderId = orderId;
}

public void setOrderDesc(String orderDesc) {
this.orderDesc = orderDesc;
}

public void setClient(Client client) {
this.client = client;
}
}

All magic happens in the Entity Client. which has a Set variable orders associated with PurcharseOrder to represent the one-to-many mapping. We will change the annoatation for Set variable orders to get different fetch when-how combinations.

package com.shengwang.demo.model;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name="client")
public class Client {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="client_id")
private int clientId;

@Column(name="client_name")
private String clientName;

//---------------------------------
// This is where the magic happens
//---------------------------------
@OneToMany(fetch=FetchType.LAZY,mappedBy="client")
private Set<PurchaseOrder> orders = new HashSet<PurchaseOrder>();


public int getClientId() {
return clientId;
}
public String getClientName() {
return clientName;
}

public Set<PurchaseOrder> getPurchaseOrders() {
return orders;
}
public void setClientId(int clientId) {
this.clientId = clientId;
}
public void setClientName(String clientName) {
this.clientName = clientName;
}
public void setPurchaseOrders(Set<PurchaseOrder> orders) {
this.orders = orders;
}
}

2.2 demo code snippet


Following code snippet is used to show how the different fetch combinations effect. We'll keep running this code on different when-how fetch combinations to demonstrate differents effects

@Override
@Transactional
public void printOrdersForEveryClient() {
List <Client> clients;
Criteria criteria;
criteria = sessionFactory.getCurrentSession().createCriteria(Client.class);
clients = criteria.list(); // checkpoint-1
System.out.println("clients.size="+clients.size());

for (Client client: clients) {
System.out.println("client : "+ client.getClientId());
System.out.println(""+client.getPurchaseOrders().size()); // checkpoint-2
Set <PurchaseOrder> orders = client.getPurchaseOrders(); // checkpoint-3
for (PurchaseOrder order : orders) {
System.out.println(order.getOrderId()+","+order.getOrderDesc());
}
}
}

The method printOrdersForEveryClient() is supposed to print out purchase orders for all clients one by one. The comments checkpoint1-4 is added as anchors to locate where the database accessing happens.


3. Behaviors of When+How fetch combinations


Let's try different When-How fetch combinations on the one-to-many(client-to-purchase order) mapping,  see what really happens. All the following SQL clauses are NOT the original Hibernate generated ones, but simplified to make them more understandable.


3.1 Eager + Join


Changing the definition of Client entity, set when to eager by "fetch=FetchType.EAGER", set how to join by @Fetch(FetchMode.JOIN). Since join is the default behavior for eager, annotation  @Fetch(FetchMode.JOIN) can be omitted.

@Entity
@Table(name="client")
public class Client {
// omit other fields

//---------------------------------
// This is where the magic happens
//---------------------------------
@OneToMany(fetch=FetchType.EAGER,mappedBy="client",cascade=CascadeType.PERSIST)
private Set<PurchaseOrder> orders = new HashSet<PurchaseOrder>();

// omit getters & setters
}

The database accessing happens only in 1 place:
select a.*,  b.* from client a left outer join purchase_order b on a.client_id=b.client_id      at checkpoint-1


Suppose there are 5 rows in client table and every client have 10 purchase orders in purchase_order table. The result list size at checkpoint-1 is not 5, but 5x10 = 50. This will make the method printOrdersForEveryClient() doesn't work as design. 


3.2 Lazy + Select (default behavior)


The default when is lazy, and the default how for lazy is select.


The database accessing happens in  2 places:
select *  from client   at checkpoint-1
select * from purchase_order  where client_id=?     at checkpoint-2


Since the checkpoint-2 is in the for loop, every loop will issue a sql query to database, perfectly demonstrate the so-called 'N+1' problems.
You may also notice that although lazy fetch is used, the database accessing immediately happens when querying the clients.  That's because the lazy fetch only works for query entity by primary key.


3.3 Eager+ Select


Changing the definition of Client entity, set when to eager by "fetch=FetchType.EAGER", set how to join by @Fetch(FetchMode.SELECT)

@Entity
@Table(name="client")
public class Client {
// omit other fields

//---------------------------------
// This is where the magic happens
//---------------------------------
@OneToMany(fetch=FetchType.EAGER,mappedBy="client",cascade=CascadeType.PERSIST)
@Fetch(FetchMode.SELECT)
private Set<PurchaseOrder> orders = new HashSet<PurchaseOrder>();

// omit getters & setters
}

The database accessing happens only in 1 place, but N+1 SQL clauses:


select * from client                                                                             at checkpoint-1
select * from purchase_order where client_id=?                at checkpoint-1               
select * from purchase_order where client_id=?               
at checkpoint-1
select * from purchase_order where client_id=?                at checkpoint-1
select * from purchase_order where client_id=?                at checkpoint-1
select * from purchase_order where client_id=?                at checkpoint-1

The query in java also creates N+1 SQL clauses, but all at same time. One to get all clients and 5 to get orders for each client.  (There are 5 clients in the client table) 


3.4 Lazy + Batch


Changing the definition of Client entity, set when to lazy by "fetch=FetchType.LAZY", set how to batch by @Fetch(FetchMode.SELECT) and @BatchSize(size=3) . Since select is the default behavior for lazy, annotation  @Fetch(FetchMode.SELECT) can be omitted.

@Entity
@Table(name="client")
public class Client {
// omit other fields

//---------------------------------
// This is where the magic happens
//---------------------------------
@OneToMany(fetch=FetchType.LAZY,mappedBy="client",cascade=CascadeType.PERSIST)
@BatchSize(size=3)
private Set<PurchaseOrder> orders = new HashSet<PurchaseOrder>();

// omit getters & setters
}

The database accessing happens in 2 places:
select * from client                                                                             at checkpoint-1
select * from purchase_order where client_id in (?, ?, ?)             at checkpoint-2               


Unlike the select, which accesses database N+1 times,  batch fetch accesses database (N/batchSize +1 ) times. In our demo, there are 5 clients in the table,  batch size is 3, total database accessing counts = celling(5/3)+1=3. 


3.5 Eager + Batch


Changing the definition of Client entity, set when to eager by "fetch=FetchType.EAGER", set how to batch by @Fetch(FetchMode.SELECT) and @BatchSize(size=3)

@Entity
@Table(name="client")
public class Client {
// omit other fields

//---------------------------------
// This is where the magic happens
//---------------------------------
@OneToMany(fetch=FetchType.LAZY,mappedBy="client",cascade=CascadeType.PERSIST)
@Fetch(FetchMode.SELECT)
@BatchSize(size=3)
private Set<PurchaseOrder> orders = new HashSet<PurchaseOrder>();

// omit getters & setters
}

The database accessing happens in 1 place:
select * from client                                                                             at checkpoint-1
select * from purchase_order where client_id in (?, ?, ?)             at checkpoint-1               


Compare to Lazy+Batch, Eager+Batch  create same amount SQL and exactly same SQL clauses. but will no wait for the first time accessing contents of client entity, but immediately load all clients' associations when query client entity. 


3.6 Lazy + Subselect


Changing the definition of Client entity, set when to lazy by "fetch=FetchType.LAZY", set how to subselect by @Fetch(FetchMode.SUBSELECT)

@Entity
@Table(name="client")
public class Client {
// omit other fields

//---------------------------------
// This is where the magic happens
//---------------------------------
@OneToMany(fetch=FetchType.LAZY,mappedBy="client",cascade=CascadeType.PERSIST)
@Fetch(FetchMode.SUBSELECT)
private Set<PurchaseOrder> orders = new HashSet<PurchaseOrder>();

// omit getters & setters
}

The database accessing happens in 2 places:
select * from client                                                                             at checkpoint-1
select a.* from purchase_order a where a.client_id in (select b.client_id from client b)        at checkpoint-2


Unlike the select(N+1) or batch (N/batchsize+1), subselect only access database once to get all associations for the previous query.  The first time in the loop cause the second SQL  and rest of the loop won't access database anymore.  Totally the code accesses database twice.


3.7 Eager+ Subselect


Changing the definition of Client entity, set when to eager by "fetch=FetchType.EAGER", set how to subselect by @Fetch(FetchMode.SUBSELECT)

@Entity
@Table(name="client")
public class Client {
// omit other fields

//---------------------------------
// This is where the magic happens
//---------------------------------
@OneToMany(fetch=FetchType.EAGER,mappedBy="client",cascade=CascadeType.PERSIST)
@Fetch(FetchMode.SUBSELECT)
private Set<PurchaseOrder> orders = new HashSet<PurchaseOrder>();

// omit getters & setters
}

The database accessing happens in 1 place:
select * from client                                                                             at checkpoint-1
select a.* from purchase_order a where a.client_id in (select b.client_id from client b)        at checkpoint-1


Compare to Lazy+Subselect, Eager+Subselect  create same amount SQL and exactly same SQL clauses. but will no wait for the first time accessing contents of client entity, but immediately load all clients' associations when query client entity.


3.8 Extra Lazy+ Batch


Changing the definition of Client entity, set when to extra lazy by "fetch=FetchType.LAZY" and @LazyCollection(LazyCollectionOption.EXTRA), set how to batch by @Fetch(FetchMode.SUBSELECT)  and @BatchSize(size=3)

@Entity
@Table(name="client")
public class Client {
// omit other fields

//---------------------------------
// This is where the magic happens
//---------------------------------
@OneToMany(fetch=FetchType.LAZY,mappedBy="client",cascade=CascadeType.PERSIST)
@LazyCollection(LazyCollectionOption.EXTRA)
@Fetch(FetchMode.SELECT)
@BatchSize(size=3)
private Set<PurchaseOrder> orders = new HashSet<PurchaseOrder>();

// omit getters & setters
}

The database accessing happens in 3 places:
select * from client                                                                             at checkpoint-1
select count(order_id) from purchase_order where client_id= ?                         at checkpoint-2
select * from purchase_order where client_id in (?, ?, ?)              at checkpoint-3               


Compare to Lazy+Batch, Extra Lazy+Batch  create one more SQL clause to avoid getting  all collections contents back when possible.  Extra Lazy is not supported by other persistence providers like EclipseLink. In EclipseLink developer has to manually define a query to get the collection's size without get all contents back.


4. More to notice


The batch size doesn't mean how many rows will be fetched from the associations, but means how many associations to be fetched.  For example using batch fetch,  if there are 1000 purchase orders for each client, batch size = 3, every batch SQL will fetch 3 clients' associations, totally 3000 rows, from purchase_order table.  If only part of the collections are needed, pagination is the solution.

Tuesday, December 9, 2014

How to create Java classes from existing tables in database for JPA

If JPA is your persistence layer in your project and you have tables already defined in database. You can use JPA tools in Eclipse to automatically create corresponding Java Entity classes from those tables in database.

In this article, Java JPA entities will be created from an oracle database on LAN.

1. what you need

  • Eclipse 4.3 +  ( In this article, Eclipse Java EE version 4.3.2 kepler is used )
  • Database connection configuration in Eclipse. In eclipse, configure a database connection to the oracle database.  If you don't know how to do that, read this article first How to add oracle DB connection in Eclipse.

2. Make sure you have JPA support enabled in your projects

Righ click on the project name and select "Properties"

Snap_2014.12.09 14.30.34_003

Use project facets if project facets not enabled

Snap_2014.12.09 10.02.48_001

Click the "JPA" if it's not selected, then click "OK" to close the project properties window.

Snap_2014.12.09 14.34.20_004

3. create Java classes from tables

After enabling JPA in project properties, now right click you eclipse project name again, you should see a new context menu item "JPA tools" appears. Choose "Generate Entities from tables"

If you see the "JPA tools" menu but the sub menu don't have "Generate Entities from tables"  item, make sure you right click on the project name instead of a package or a class file.

Snap_2014.12.09 14.49.33_006 

Select a database connection to let Eclipse get the tables  used to generated class from.  (See another tutorial on  how to configure a database connection in Eclipse)

Snap_2014.12.09 15.04.08_007

After connected to the database, schema and tables will be listed below, choose the tables you need in your Java project and click "Next"Snap_2014.12.09 15.07.21_008

In this tutorial  2 tables are selected. There is a  foreign key between 2 tables. Logically one  platform can have more than one devices. It's a "1 to many" mapping.

Next Eclipse automatically create associations between tables you select.  Click each association to see the details.

Snap_2014.12.09 15.20.46_009

In the final step, Eclipse offers the chance to change generated Java class name and the field name inside the generated java class.

Snap_2014.12.09 15.28.13_011

Snap_2014.12.09 15.29.02_012

Click "finish" and the Java classes will be created.  For example one of the Entity class created looks like:

Snap_2014.12.09 15.38.05_013

The created Java Entity class is well annotated and ready for use!

Monday, December 8, 2014

How to add oracle DB connection in Eclipse

Have a DB connection in Eclipse will be very helpful if you need use persistence frameworks like Hibernate or JPA.  It's normally a prerequisite for other functions, for example let eclipse create java entities class from database tables automatically.  Here's how to configure oracle connection in Eclipse.

1. what you need

  • Oracle JDBC driver. ( A jar file may look like ojdbcxxx.jar, if you don't have it on your local file system, download it from oracle website)

2. open "Data Source Explorer" view in Eclipse

From menu, select "window"->"Show View"->"Other"

Snap_2014.12.09 11.23.04_014

Next, Choose "Data Source Explorer" from category "Data Management"

Snap_2014.12.09 10.04.24_002

Then you should have the view opened.

3. Add new connection

Right click on the "Database Connection" in the "Data Source Explorer" view we just opened.  choose "New..."

Snap_2014.12.09 10.06.49_003 

Choose database type ( here is Oracle), give a name for this connection (here is "oracle")

Snap_2014.12.09 10.08.52_005

Next, select the oracle driver for this connection by click the follow icon pointed by the arrow.

Snap_2014.12.09 10.13.26_006

Next, choose oracle version (I'm using oracle 11 for this demo, you can pick up your version) ,  and click the "Jar List" tab to set the driver file path

Snap_2014.12.09 10.14.51_007

In the "Jar List" tab, replace the default non-exists oracle driver file, which is ojdbc14.jar, with the real one  in you local file system, which is d:\ojdbc6.jar

Snap_2014.12.09 10.17.27_009

Snap_2014.12.09 10.19.15_010 

Close the above window,  next provide connection information.

Snap_2014.12.09 10.22.01_012

Use "Test Connection" button to make sure every thing is OK, then Finish.

4. After Connection created

You can see the new oracle DB connection appears in the "Data Source Explorer" view.

Snap_2014.12.09 11.50.04_015

You can browse the database in the view within Eclipse.

Tuesday, December 2, 2014

How to disable c3p0 from writing log to screen (stderr)

Even if you have slf4j and logback configured in your project, the c3p0 insists on writing log to system error channel like this:

Snap_2014.12.03 11.17.45_001

The Eclipse console show log from c3p0 in red, because the texts are written to stderr.  The way to dismiss those red part from c3p0 is add two lines at the beginning of your code.

public static void main(String[] args) {
System.setProperty("com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL", "WARNING");
System.setProperty("com.mchange.v2.log.MLog", "com.mchange.v2.log.FallbackMLog");

// rest of your code
}


Here is the final result looks like. the redundant c3p0 log to stderr is gone.



image

Powered by Blogger.

About The Author

My Photo
Has been a senior software developer, project manager for 10+ years. Dedicate himself to Alcatel-Lucent and China Telecom for delivering software solutions.

Pages

Unordered List