Hi
I m new to Hibernate and my goal is not to do serious benchmarking testing on Hibernate. It is just to get an idea of how fast you can group data and do calculations in application layer using an ORM tool as oppose to in database. My goal is not to get perfect performance results but reasonable once for Hibernate. In other words, I just want to know that I m not way off concerning performance. However I have now changed my approach and used Spring to configure Hibernate and I think I m getting good results. I have two classes: Customer and CustomerDetail (association one to many) and I m doing grouping and calculations on data in CustomerDetail objects. In the most resent test I have run I have following situation: 1000 Customers and 1000 CustomerDetails for each Customer. The result I m getting is:
Total time to do all calculations: 2810.0 ms
Time to get customers and customerdetails: 40558 ms
This means that I m getting 1000 0000 CustomerDetails in 40 sec that is not good right?
Calculations don’t have anything to do with Hibernate but I m wondering if I can do something to make fetching of objects go even faster. Is there any transaction scope setting or Hibernate configuration I can make that is good for the kind of task that I m performing.
Here are my classes and interfaces and DAO implementations:
package se.dsv.su.dao;
import java.util.Set;
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.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import org.apache.commons.math.stat.descriptive.SummaryStatistics;
import org.springframework.beans.factory.annotation.Configurable;
@Entity
@Table(name = "Customer",schema = "Office")
public class Customer {
transient double stoptime=0;
transient double starttime=0;
transient static double totaltime;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "CustomerId")
private int customerId;
@OneToMany(mappedBy = "customerId")
private Set<CustomerDetail> customerDetails;
@ManyToOne
@JoinColumn(name = "DepartmentId", referencedColumnName = "DepartmentId", nullable = false)
private Department departmentId;
@Column(name = "customerEmailaddress", length = 255)
@NotNull
private String customerEmailaddress;
@Column(name = "customerAddress", length = 255)
@NotNull
private String customerAddress;
@Column(name = "customerName", length = 255)
@NotNull
private String customerName;
public Set<CustomerDetail> getCustomerDetails() {
return this.customerDetails;
}
public void setCustomerDetails(Set<CustomerDetail> customerDetails) {
this.customerDetails = customerDetails;
}
public Department getDepartmentId() {
return this.departmentId;
}
public void setDepartmentId(Department departmentId) {
this.departmentId = departmentId;
}
public String getCustomerEmailaddress() {
return this.customerEmailaddress;
}
public void setCustomerEmailaddress(String customerEmailaddress) {
this.customerEmailaddress = customerEmailaddress;
}
public String getCustomerAddress() {
return this.customerAddress;
}
public void setCustomerAddress(String customerAddress) {
this.customerAddress = customerAddress;
}
public String getCustomerName() {
return this.customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
public int getCustomerId() {
return this.customerId;
}
public void setCustomerId(int id) {
this.customerId = id;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("CustomerAddress: ").append(getCustomerAddress()).append(", ");
sb.append("CustomerDetails: ").append(getCustomerDetails() == null ? "null" : getCustomerDetails().size()).append(", ");
sb.append("CustomerEmailaddress: ").append(getCustomerEmailaddress()).append(", ");
sb.append("CustomerId: ").append(getCustomerId()).append(", ");
sb.append("CustomerName: ").append(getCustomerName()).append(", ");
sb.append("DepartmentId: ").append(getDepartmentId());
return sb.toString();
}
public Double getTotalRewardPoints(){
starttime = (double)System.currentTimeMillis();
SummaryStatistics stats = new SummaryStatistics();
for(CustomerDetail cd : customerDetails){
stats.addValue(cd.getRewardPoints().doubleValue());
}
return stats.getSum();
}
public Double getMaxRewardPoints(){
SummaryStatistics stats = new SummaryStatistics();
for(CustomerDetail cd : customerDetails){
stats.addValue(cd.getRewardPoints().doubleValue());
}
return stats.getMax();
}
public Double getMinRewardPoints(){
SummaryStatistics stats = new SummaryStatistics();
for(CustomerDetail cd : customerDetails){
stats.addValue(cd.getRewardPoints().doubleValue());
}
return stats.getMin();
}
public Double getMeanRewardPoints(){
SummaryStatistics stats = new SummaryStatistics();
for(CustomerDetail cd : customerDetails){
stats.addValue(cd.getRewardPoints().doubleValue());
}
stoptime = (double)System.currentTimeMillis();
return stats.getMean();
}
public Double getTotalDebt(){
starttime = (double)System.currentTimeMillis();
SummaryStatistics stats = new SummaryStatistics();
for(CustomerDetail cd : customerDetails){
stats.addValue(cd.getDebt().doubleValue());
}
return stats.getSum();
}
public Double getMaxDebt(){
SummaryStatistics stats = new SummaryStatistics();
for(CustomerDetail cd : customerDetails){
stats.addValue(cd.getDebt().doubleValue());
}
return stats.getMax();
}
public Double getMinDebt(){
SummaryStatistics stats = new SummaryStatistics();
for(CustomerDetail cd : customerDetails){
stats.addValue(cd.getDebt().doubleValue());
}
return stats.getMin();
}
public Double getMeanDebt(){
SummaryStatistics stats = new SummaryStatistics();
for(CustomerDetail cd : customerDetails){
stats.addValue(cd.getDebt().doubleValue());
}
stoptime = (double)System.currentTimeMillis();
return stats.getMean();
}
public Double getTotalCreditStore(){
starttime = (double)System.currentTimeMillis();
SummaryStatistics stats = new SummaryStatistics();
for(CustomerDetail cd : customerDetails){
stats.addValue(cd.getCreditStore().doubleValue());
}
return stats.getSum();
}
public Double getMaxCreditStore(){
SummaryStatistics stats = new SummaryStatistics();
for(CustomerDetail cd : customerDetails){
stats.addValue(cd.getCreditStore().doubleValue());
}
return stats.getMax();
}
public Double getMinCreditStore(){
SummaryStatistics stats = new SummaryStatistics();
for(CustomerDetail cd : customerDetails){
stats.addValue(cd.getCreditStore().doubleValue());
}
return stats.getMin();
}
public Double getMeanCreditStore(){
SummaryStatistics stats = new SummaryStatistics();
for(CustomerDetail cd : customerDetails){
stats.addValue(cd.getCreditStore().doubleValue());
}
stoptime = (double)System.currentTimeMillis();
return stats.getMean();
}
public Double getTotalAmountSpent(){
starttime = (double)System.currentTimeMillis();
SummaryStatistics stats = new SummaryStatistics();
for(CustomerDetail cd : customerDetails){
stats.addValue(cd.getAmountSpent().doubleValue());
}
return stats.getSum();
}
public Double getMaxAmountSpent(){
SummaryStatistics stats = new SummaryStatistics();
for(CustomerDetail cd : customerDetails){
stats.addValue(cd.getAmountSpent().doubleValue());
}
return stats.getMax();
}
public Double getMinAmountSpent(){
SummaryStatistics stats = new SummaryStatistics();
for(CustomerDetail cd : customerDetails){
stats.addValue(cd.getCreditStore().doubleValue());
}
return stats.getMin();
}
public Double getMeanAmountSpent(){
SummaryStatistics stats = new SummaryStatistics();
for(CustomerDetail cd : customerDetails){
stats.addValue(cd.getAmountSpent().doubleValue());
}
stoptime = (double)System.currentTimeMillis();
return stats.getMean();
}
public Double getTimeToDoCalculations(){
totaltime+=(stoptime -starttime);
return (stoptime -starttime);
}
public static Double getTimeToDoAllCalculations(){
return totaltime;
}
public static void clearTimeToDoAllCalculations(){
totaltime = 0;
}
}
//Customer
package se.dsv.su.dao;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
public interface ICustomerDAO {
public List<Customer> findAllCustomers();
}
//DAO interface
package se.dsv.su.dao;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
@Repository
public class CustomerDAO implements ICustomerDAO {
@PersistenceContext
private EntityManager entityManager;
public List<Customer> findAllCustomers() {
return entityManager.createQuery("SELECT o FROM Customer o", Customer.class).getResultList();
}
}
//DAO
package se.dsv.su.dao;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.PersistenceContext;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotNull;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.transaction.annotation.Transactional;
@Entity
@Table(name = "CustomerDetail",schema = "Office")
public class CustomerDetail {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "CustomerDetailID")
private int customerDetailID;
@ManyToOne
@JoinColumn(name = "CustomerId", referencedColumnName = "CustomerId", nullable = false)
private Customer customerId;
@Column(name = "AmountSpent", precision = 9, scale = 2)
@NotNull
private BigDecimal amountSpent;
@Column(name = "CreditStore", precision = 10, scale = 4)
@NotNull
private BigDecimal creditStore;
@Column(name = "CustJoinDate")
@NotNull
@Temporal(TemporalType.TIMESTAMP)
@DateTimeFormat(style = "S-")
private Date custJoinDate;
@Column(name = "CustLogintime")
@NotNull
@Temporal(TemporalType.TIMESTAMP)
@DateTimeFormat(style = "S-")
private Date custLogintime;
@Column(name = "Debt", precision = 11, scale = 5)
@NotNull
private BigDecimal debt;
@Column(name = "RewardPoints", precision = 12, scale = 6)
@NotNull
private BigDecimal rewardPoints;
public int getCustomerDetailId() {
return this.customerDetailID;
}
public void setCustomerDetailId(int id) {
this.customerDetailID = id;
}
public Customer getCustomerId() {
return this.customerId;
}
public void setCustomerId(Customer customerId) {
this.customerId = customerId;
}
public BigDecimal getAmountSpent() {
return this.amountSpent;
}
public void setAmountSpent(BigDecimal amountSpent) {
this.amountSpent = amountSpent;
}
public BigDecimal getCreditStore() {
return this.creditStore;
}
public void setCreditStore(BigDecimal creditStore) {
this.creditStore = creditStore;
}
public Date getCustJoinDate() {
return this.custJoinDate;
}
public void setCustJoinDate(Date custJoinDate) {
this.custJoinDate = custJoinDate;
}
public Date getCustLogintime() {
return this.custLogintime;
}
public void setCustLogintime(Date custLogintime) {
this.custLogintime = custLogintime;
}
public BigDecimal getDebt() {
return this.debt;
}
public void setDebt(BigDecimal debt) {
this.debt = debt;
}
public BigDecimal getRewardPoints() {
return this.rewardPoints;
}
public void setRewardPoints(BigDecimal rewardPoints) {
this.rewardPoints = rewardPoints;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("AmountSpent: ").append(getAmountSpent()).append(", ");
sb.append("CreditStore: ").append(getCreditStore()).append(", ");
sb.append("CustJoinDate: ").append(getCustJoinDate()).append(", ");
sb.append("CustLogintime: ").append(getCustLogintime()).append(", ");
sb.append("CustomerDetailId: ").append(getCustomerDetailId()).append(", ");
sb.append("CustomerId: ").append(getCustomerId()).append(", ");
sb.append("Debt: ").append(getDebt()).append(", ");
sb.append("RewardPoints: ").append(getRewardPoints());
return sb.toString();
}
}
//CustomerDetail
Webb application is using MVC pattern, here is my Controller class where I have set timestamps
package se.dsv.su.web;
import java.util.List;
import java.util.Map;
import java.lang.System;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import se.dsv.su.dao.Customer;
import se.dsv.su.dao.ICustomerDAO;
@RequestMapping("/customers")
@Controller
public class CustomerController {
@Autowired
private ICustomerDAO customerDAO;
private long timetogetcustomers;
public static long timetogetcustomerobjects;
@RequestMapping(method = RequestMethod.GET)
public String customer(Model uiModel) {
/*Affärslogik*/
Long getcustomersstart = System.currentTimeMillis();
List<Customer> customers = customerDAO.findAllCustomers();
Long getcustomersstop = System.currentTimeMillis();
timetogetcustomerobjects = 0;
timetogetcustomers = (getcustomersstop - getcustomersstart);
timetogetcustomerobjects = timetogetcustomers;
uiModel.addAttribute("timetogetcustomers", timetogetcustomers);
uiModel.addAttribute("customers", customers);
return "customers";
}
@RequestMapping(value ="/rewardpoints" , method = RequestMethod.GET)
public String rewardpoints(Model uiModel) {
Long getcustomersstart = System.currentTimeMillis();
List<Customer> customers = customerDAO.findAllCustomers();
System.out.println(customers);
Long getcustomersstop = System.currentTimeMillis();
timetogetcustomerobjects = 0;
timetogetcustomers = (getcustomersstop - getcustomersstart);
timetogetcustomerobjects = timetogetcustomers;
uiModel.addAttribute("timetogetcustomers", timetogetcustomers);
uiModel.addAttribute("customers", customers);
return "showrewardpoints";
}
@RequestMapping(value ="/creditstore" , method = RequestMethod.GET)
public String creditstore(Model uiModel) {
Long getcustomersstart = System.currentTimeMillis();
List<Customer> customers = customerDAO.findAllCustomers();
Long getcustomersstop = System.currentTimeMillis();
timetogetcustomerobjects = 0;
timetogetcustomers = (getcustomersstop - getcustomersstart);
timetogetcustomerobjects = timetogetcustomers;
uiModel.addAttribute("timetogetcustomers", timetogetcustomers);
uiModel.addAttribute("customers", customers);
return "showcreditstore";
}
@RequestMapping(value ="/debt" , method = RequestMethod.GET)
public String debt(Model uiModel) {
Long getcustomersstart = System.currentTimeMillis();
List<Customer> customers = customerDAO.findAllCustomers();
Long getcustomersstop = System.currentTimeMillis();
timetogetcustomerobjects = 0;
timetogetcustomers = (getcustomersstop - getcustomersstart);
timetogetcustomerobjects = timetogetcustomers;
uiModel.addAttribute("timetogetcustomers", timetogetcustomers);
uiModel.addAttribute("customers", customers);
return "showdebt";
}
@RequestMapping(value ="/amountspent" , method = RequestMethod.GET)
public String amountspent(Model uiModel) {
Long getcustomersstart = System.currentTimeMillis();
List<Customer> customers = customerDAO.findAllCustomers();
Long getcustomersstop = System.currentTimeMillis();
timetogetcustomerobjects = 0;
timetogetcustomers = (getcustomersstop - getcustomersstart);
timetogetcustomerobjects = timetogetcustomers;
uiModel.addAttribute("timetogetcustomers", timetogetcustomers);
uiModel.addAttribute("customers", customers);
return "showamountspent";
}
@RequestMapping(value ="/clearlists" , method = RequestMethod.POST)
public String clearLists(Model uiModel) {
TimerUtil.clearLists();
System.out.println("listorna har rensats");
return "chart";
}
@RequestMapping(value ="/showchart" , method = RequestMethod.POST)
public String showchart(Model uiModel) {
Map <Number,String> timetodocalculationsmap = TimerUtil.getTimestodocalculations();
Map <Number,String> timetogetobjectsmap = TimerUtil.getTimestogetobjects();
Map <Number,String> totaltimemap = TimerUtil.getTotaltime();
Map <Number, String> timestogetJDBCresultset = TimerUtil.getTimestogetJDBCresultset();
uiModel.addAttribute("timetodocalculationsmap", timetodocalculationsmap);
uiModel.addAttribute("timetogetobjectsmap", timetogetobjectsmap);
uiModel.addAttribute("totaltimemap", totaltimemap);
uiModel.addAttribute("timetogetJDBCresultsetmap", timestogetJDBCresultset);
System.out.println("Mapparna läggs in");
return "chart";
}
}
Dont worry I m showing timeing results only once on each JSP
Here is My Hibernate Spring configured XML file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/ ... ce_2_0.xsd">
<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>
<!-- value="create" to build a new database on each run; value="update" to modify an existing database; value="create-drop" means the same as "create" but also drops tables when Hibernate closes; value="validate" makes no changes to the database -->
<property name="hibernate.hbm2ddl.auto" value="validate"/>
<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.DefaultNamingStrategy"/>
<property name="hibernate.connection.charSet" value="UTF-8"/>
<!-- Uncomment the following two properties for JBoss only -->
<!-- property name="hibernate.validator.apply_to_ddl" value="false" /-->
<!-- property name="hibernate.validator.autoregister_listeners" value="false" /-->
</properties>
</persistence-unit>
</persistence>
And here is my spring ApplicationContext XML file where I m configuring datasource. I m guessing that EntetyManager is wrapper class for Hibernate Session class and EntityManagerFactory is like Hibernates SessionFactory class. Don’t worry about JdbcTemplate bean I m using it for something else.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/a ... op-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/b ... ns-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/c ... xt-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/j ... ee-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/t ... tx-3.0.xsd">
<!--
This will automatically locate any and all property files you have
within your classpath, provided they fall under the META-INF/spring
directory. The located property files are parsed and their values can
then be used within application context files in the form of
${propertyKey}.
-->
<context:property-placeholder location="classpath*:META-INF/spring/*.properties"/>
<!--
Turn on AspectJ @Configurable support. As a result, any time you
instantiate an object, Spring will attempt to perform dependency
injection on that object. This occurs for instantiation via the "new"
keyword, as well as via reflection. This is possible because AspectJ
is used to "weave" Roo-based applications at compile time. In effect
this feature allows dependency injection of any object at all in your
system, which is a very useful feature (without @Configurable you'd
only be able to dependency inject objects acquired from Spring or
subsequently presented to a specific Spring dependency injection
method). Roo applications use this useful feature in a number of
areas, such as @PersistenceContext injection into entities.
-->
<context:spring-configured/>
<!--
This declaration will cause Spring to locate every @Component,
@Repository and @Service in your application. In practical terms this
allows you to write a POJO and then simply annotate the new POJO as an
@Service and Spring will automatically detect, instantiate and
dependency inject your service at startup time. Importantly, you can
then also have your new service injected into any other class that
requires it simply by declaring a field for your service inside the
relying class and Spring will inject it. Note that two exclude filters
are declared. The first ensures that Spring doesn't spend time
introspecting Roo-specific ITD aspects. The second ensures Roo doesn't
instantiate your @Controller classes, as these should be instantiated
by a web tier application context. Refer to web.xml for more details
about the web tier application context setup services.
Furthermore, this turns on @Autowired, @PostConstruct etc support. These
annotations allow you to use common Spring and Java Enterprise Edition
annotations in your classes without needing to do any special configuration.
The most commonly used annotation is @Autowired, which instructs Spring to
dependency inject an object into your class.
-->
<context:component-scan base-package="se.dsv" />
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
<property name="driverClassName" value="${database.driverClassName}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="true"/>
<property name="testWhileIdle" value="true"/>
<property name="timeBetweenEvictionRunsMillis" value="1800000"/>
<property name="numTestsPerEvictionRun" value="3"/>
<property name="minEvictableIdleTimeMillis" value="1800000"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="persistenceUnitName" value="persistenceUnit"/>
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
Thank you for your help