Sfoglia il codice sorgente

Merge pull request #814 from martin-g/wicket-plain-jdbc

Wicket - Use plain jdbc, drop Hibernate
Hamilton Turner 11 anni fa
parent
commit
c421e6f9e6

+ 1 - 1
.travis.yml

@@ -20,7 +20,7 @@ env:
     #
     # Here's a bash one-liner if you need to update this: 
     # toolset/run-tests.py --list-tests | while read line ; do
-    #    echo "    - TEST=$line"
+    #    echo "    - TESTDIR=$line"
     # done    
     - TESTDIR=activeweb
     - TESTDIR=aspnet

+ 12 - 20
wicket/pom.xml

@@ -20,8 +20,10 @@
 		</license>
 	</licenses>
 	<properties>
-		<wicket.version>6.14.0</wicket.version>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+		<wicket.version>6.16.0</wicket.version>
 		<jetty.version>8.1.14.v20131031</jetty.version>
+		<slf4j.version>1.7.7</slf4j.version>
 	</properties>
 	<dependencies>
 		<!--  WICKET DEPENDENCIES -->
@@ -30,19 +32,20 @@
 			<artifactId>wicket-core</artifactId>
 			<version>${wicket.version}</version>
 		</dependency>
-		<!-- OPTIONAL DEPENDENCY
+
+		<!-- a faster DataSource -->
 		<dependency>
-			<groupId>org.apache.wicket</groupId>
-			<artifactId>wicket-extensions</artifactId>
-			<version>${wicket.version}</version>
+			<groupId>com.zaxxer</groupId>
+			<artifactId>HikariCP</artifactId>
+			<version>1.4.0</version>
+			<scope>compile</scope>
 		</dependency>
-		-->
 
 		<!-- LOGGING DEPENDENCIES - LOG4J -->
 		<dependency>
 			<groupId>org.slf4j</groupId>
 			<artifactId>slf4j-log4j12</artifactId>
-			<version>1.7.6</version>
+			<version>${slf4j.version}</version>
 		</dependency>
 		<dependency>
 			<groupId>log4j</groupId>
@@ -71,22 +74,11 @@
 			<artifactId>jackson-databind</artifactId>
 			<version>2.3.2</version>
 		</dependency>
-		            
-		<dependency>
-		  <groupId>org.hibernate</groupId>
-		  <artifactId>hibernate-core</artifactId>
-		  <version>4.1.1.Final</version>
-		</dependency>
 
-		<dependency>
-		  <groupId>com.google.inject</groupId>
-		  <artifactId>guice</artifactId>
-		  <version>3.0</version>
-		</dependency>
 		<dependency>
 		  <groupId>mysql</groupId>
 		  <artifactId>mysql-connector-java</artifactId>
-		  <version>5.1.29</version>
+		  <version>5.1.31</version>
 		</dependency>
 	</dependencies>
 	<build>
@@ -127,7 +119,7 @@
 				<inherited>true</inherited>
 				<groupId>org.apache.maven.plugins</groupId>
 				<artifactId>maven-compiler-plugin</artifactId>
-				<version>2.5.1</version>
+				<version>3.1</version>
 				<configuration>
 					<source>1.7</source>
 					<target>1.7</target>

+ 30 - 16
wicket/src/main/java/hellowicket/HelloDbResponse.java

@@ -1,12 +1,14 @@
 package hellowicket;
 
-import java.io.IOException;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
 import java.util.concurrent.ThreadLocalRandom;
 
+import javax.sql.DataSource;
+
 import org.apache.wicket.request.resource.AbstractResource;
 import org.apache.wicket.util.string.StringValue;
-import org.hibernate.IdentifierLoadAccess;
-import org.hibernate.Session;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 
@@ -32,8 +34,6 @@ public class HelloDbResponse extends AbstractResource
       qs = 500;
     }
     final int queries = qs;
-    final World[] worlds = new World[queries];
-    final ThreadLocalRandom random = ThreadLocalRandom.current();
 
     final ResourceResponse response = new ResourceResponse();
     response.setContentType(CONTENT_TYPE);
@@ -42,18 +42,32 @@ public class HelloDbResponse extends AbstractResource
     {
       public void writeData(Attributes attributes)
       {
-        final Session session = HibernateUtil.getSessionFactory().openSession();
-
-        IdentifierLoadAccess loader = session.byId(World.class);
-        for (int i = 0; i < queries; i++)
-        {
-          worlds[i] = (World) loader.load(random.nextInt(DB_ROWS) + 1);
-        }
-
-        session.close();
-
         try
         {
+          final ThreadLocalRandom random = ThreadLocalRandom.current();
+          DataSource dataSource = WicketApplication.get().getDataSource();
+          World[] worlds = new World[queries];
+          try (Connection connection = dataSource.getConnection())
+          {
+            try (PreparedStatement statement = connection.prepareStatement(
+                       "SELECT * FROM World WHERE id = ?",
+                       ResultSet.TYPE_FORWARD_ONLY,
+                       ResultSet.CONCUR_READ_ONLY))
+            {
+              for (int i = 0; i < queries; i++)
+              {
+                  statement.setInt(1, random.nextInt(DB_ROWS) + 1);
+                  try (ResultSet resultSet = statement.executeQuery())
+                  {
+                      resultSet.next();
+                      worlds[i] = new World(
+                              resultSet.getInt("id"),
+                              resultSet.getInt("randomNumber"));
+                  }
+              }
+            }
+          }
+
           String data;
           if (queriesParam.isNull())
           {
@@ -67,7 +81,7 @@ public class HelloDbResponse extends AbstractResource
           }
           attributes.getResponse().write(data);
         }
-        catch (IOException ex)
+        catch (Exception ex)
         {
           // do nothing
         }

+ 0 - 26
wicket/src/main/java/hellowicket/HibernateUtil.java

@@ -1,26 +0,0 @@
-package hellowicket;
-
-import org.hibernate.SessionFactory;
-import org.hibernate.cfg.Configuration;
-
-// http://stackoverflow.com/questions/4934330/org-hibernate-hibernateexception-hibernate-cfg-xml-not-found
-public class HibernateUtil {
-
-    private static final SessionFactory sessionFactory = buildSessionFactory();
-
-    private static SessionFactory buildSessionFactory() {
-        try {
-            // Create the SessionFactory from hibernate.cfg.xml
-            return new Configuration().configure().buildSessionFactory();
-        }
-        catch (Throwable ex) {
-            // Make sure you log the exception, as it might be swallowed
-            System.err.println("Initial SessionFactory creation failed." + ex);
-            throw new ExceptionInInitializerError(ex);
-        }
-    }
-
-    public static SessionFactory getSessionFactory() {
-        return sessionFactory;
-    }
-}

+ 63 - 6
wicket/src/main/java/hellowicket/WicketApplication.java

@@ -1,17 +1,24 @@
 package hellowicket;
 
-import hellowicket.plaintext.HelloTextReference;
-import hellowicket.dbupdates.HelloDbUpdatesReference;
-import hellowicket.fortune.FortunePage;
-import org.apache.wicket.RuntimeConfigurationType;
+import javax.naming.InitialContext;
+import javax.sql.DataSource;
+
 import org.apache.wicket.protocol.http.WebApplication;
 import org.apache.wicket.settings.IRequestCycleSettings;
 
+import com.zaxxer.hikari.HikariDataSource;
+
+import hellowicket.dbupdates.HelloDbUpdatesReference;
+import hellowicket.fortune.FortunePage;
+import hellowicket.plaintext.HelloTextReference;
+
 /**
  * Application object for your web application..
  */
 public class WicketApplication extends WebApplication
 {
+	private DataSource db;
+
 	@Override
 	public Class<HomePage> getHomePage()
 	{
@@ -23,6 +30,8 @@ public class WicketApplication extends WebApplication
 	{
 		super.init();
 
+		db = newDataSource();
+
 		// mount the resources under test
 		mountResource("/json", new HelloJsonReference());
 		mountResource("/db", new HelloDbReference());
@@ -41,8 +50,56 @@ public class WicketApplication extends WebApplication
 	}
 
 	@Override
-	public RuntimeConfigurationType getConfigurationType()
+	protected void onDestroy()
 	{
-		return RuntimeConfigurationType.DEPLOYMENT;
+		if (db instanceof HikariDataSource) {
+			((HikariDataSource)db).close();
+		}
+		super.onDestroy();
+	}
+
+	private boolean useResinDataSource()
+	{
+		return false;
+	}
+
+	public static WicketApplication get()
+	{
+		return (WicketApplication) WebApplication.get();
+	}
+
+	public DataSource getDataSource()
+	{
+		return db;
+	}
+
+	private DataSource newDataSource()
+	{
+		DataSource dataSource;
+		try
+		{
+			Class.forName("com.mysql.jdbc.Driver");
+
+			if (useResinDataSource())
+			{
+				InitialContext jndiContext = new InitialContext();
+				dataSource = (DataSource) jndiContext.lookup("java:comp/env/jdbc/hello_world");
+			}
+			else
+			{
+				// use faster DataSource impl
+				HikariDataSource ds = new HikariDataSource();
+				ds.setJdbcUrl("jdbc:mysql://localhost:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true");
+				ds.setDriverClassName("com.mysql.jdbc.Driver");
+				ds.setUsername("benchmarkdbuser");
+				ds.setPassword("benchmarkdbpass");
+				dataSource = ds;
+			}
+		} catch (Exception x)
+		{
+			throw new RuntimeException("Cannot create the data source", x);
+		}
+
+		return dataSource;
 	}
 }

+ 9 - 8
wicket/src/main/java/hellowicket/World.java

@@ -1,15 +1,16 @@
 package hellowicket;
 
-import javax.persistence.Entity;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-
-@Entity
 public class World
 {
-  @Id
-  @GeneratedValue(strategy = GenerationType.IDENTITY)
   public int id;
   public int randomNumber;
+
+  public World()
+  {
+  }
+
+  public World(int id, int randomNumber) {
+    this.id = id;
+    this.randomNumber = randomNumber;
+  }
 }

+ 39 - 41
wicket/src/main/java/hellowicket/dbupdates/HelloDbUpdatesResource.java

@@ -1,22 +1,18 @@
 package hellowicket.dbupdates;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.concurrent.ThreadLocalRandom;
+
+import javax.sql.DataSource;
 
 import org.apache.wicket.request.resource.AbstractResource;
-import org.hibernate.CacheMode;
-import org.hibernate.Query;
-import org.hibernate.ScrollMode;
-import org.hibernate.ScrollableResults;
-import org.hibernate.Session;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 
-import hellowicket.HibernateUtil;
+import hellowicket.WicketApplication;
 import hellowicket.World;
-import org.hibernate.Transaction;
 
 /**
  * A resource that implements the requirements for
@@ -49,49 +45,51 @@ public class HelloDbUpdatesResource extends AbstractResource
     response.setWriteCallback(new WriteCallback() {
       public void writeData(Attributes attributes)
       {
-        Random random = new Random();
-
-        List<World> worldsForJson = new ArrayList<>();
-
-        Session session = HibernateUtil.getSessionFactory().openSession();
-        Transaction tx = session.beginTransaction();
-
-        // update in batches. See http://docs.jboss.org/hibernate/core/3.3/reference/en/html/batch.html#batch-update
-        ScrollableResults worlds = session.createQuery("from World")
-           .setMaxResults(queries)
-           .setCacheMode(CacheMode.IGNORE)
-           .scroll(ScrollMode.FORWARD_ONLY);
-        int count=0;
-        while (worlds.next())
+        try
         {
-          World world = (World) worlds.get(0);
-          world.randomNumber = random.nextInt(DB_ROWS) + 1;
-          worldsForJson.add(world);
-          if ( ++count % 500 == 0 )
+          final ThreadLocalRandom random = ThreadLocalRandom.current();
+          DataSource dataSource = WicketApplication.get().getDataSource();
+
+          World[] worlds = new World[queries];
+          try (Connection connection = dataSource.getConnection();
+               PreparedStatement query = connection.prepareStatement(
+                       "SELECT * FROM World WHERE id = ?",
+                       ResultSet.TYPE_FORWARD_ONLY,
+                       ResultSet.CONCUR_READ_ONLY);
+               PreparedStatement update = connection.prepareStatement(
+                       "UPDATE World SET randomNumber = ? WHERE id= ?"))
           {
-            //flush a batch of updates and release memory
-            session.flush();
-            session.clear();
+            for (int i = 0; i < queries; i++)
+            {
+              query.setInt(1, random.nextInt(DB_ROWS) + 1);
+              World world;
+              try (ResultSet resultSet = query.executeQuery())
+              {
+                resultSet.next();
+                world = new World(
+                    resultSet.getInt("id"),
+                    resultSet.getInt("randomNumber"));
+              }
+              world.randomNumber = random.nextInt(DB_ROWS) + 1;
+              update.setInt(1, world.randomNumber);
+              update.setInt(2, world.id);
+              update.executeUpdate();
+              worlds[i] = world;
+            }
           }
-        }
-
-        tx.commit();
-        session.close();
 
-        try
-        {
           String data;
           if (queries == 1)
           {
-              data = HelloDbUpdatesResource.mapper.writeValueAsString(worldsForJson.get(0));
+              data = HelloDbUpdatesResource.mapper.writeValueAsString(worlds[0]);
           }
           else
           {
-              data = HelloDbUpdatesResource.mapper.writeValueAsString(worldsForJson);
+              data = HelloDbUpdatesResource.mapper.writeValueAsString(worlds);
           }
           attributes.getResponse().write(data);
         }
-        catch (IOException ex)
+        catch (Exception ex)
         {
           // do nothing
         }

+ 23 - 12
wicket/src/main/java/hellowicket/fortune/Fortune.java

@@ -1,18 +1,29 @@
 package hellowicket.fortune;
 
-import javax.persistence.Entity;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-
-/**
- *
- */
-@Entity
-public class Fortune
+public class Fortune implements Comparable<Fortune>
 {
-	@Id
-	@GeneratedValue(strategy = GenerationType.IDENTITY)
 	public int id;
 	public String message;
+
+	public Fortune()
+	{
+	}
+
+	/**
+	 * Constructs a new fortune object with the given parameters.
+	 *
+	 * @param id the ID of the fortune
+	 * @param message the message of the fortune
+	 */
+	public Fortune(int id, String message)
+	{
+		this.id = id;
+		this.message = message;
+	}
+
+	@Override
+	public int compareTo(Fortune other)
+	{
+		return message.compareTo(other.message);
+	}
 }

+ 29 - 28
wicket/src/main/java/hellowicket/fortune/FortunePage.java

@@ -1,39 +1,52 @@
 package hellowicket.fortune;
 
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.List;
 
+import javax.sql.DataSource;
+
+import hellowicket.WicketApplication;
 import org.apache.wicket.markup.html.WebPage;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.list.ListItem;
 import org.apache.wicket.markup.html.list.ListView;
-import org.hibernate.Query;
-import org.hibernate.Session;
-
-import hellowicket.HibernateUtil;
 
 /**
  * A page that loads all fortune cookies
  */
 public class FortunePage extends WebPage
 {
-  public FortunePage()
+  public FortunePage() throws Exception
   {
-    Session session = HibernateUtil.getSessionFactory().openSession();
+    List<Fortune> fortunes = new ArrayList<>(10000);
 
-    Query query = session.createQuery("from Fortune");
-    query.setReadOnly(true);
-    List list = query.list();
-    List<Fortune> fortunes = new ArrayList<Fortune>(list);
-    session.close();
-
-    Fortune newFortune = new Fortune();
-    newFortune.message = "Additional fortune added at request time.";
+    Fortune newFortune = new Fortune(0, "Additional fortune added at request time.");
     fortunes.add(newFortune);
 
-    sort(fortunes);
+    DataSource dataSource = WicketApplication.get().getDataSource();
+    try (Connection connection = dataSource.getConnection())
+    {
+      try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM Fortune",
+              ResultSet.TYPE_FORWARD_ONLY,
+              ResultSet.CONCUR_READ_ONLY))
+      {
+          try (ResultSet resultSet = statement.executeQuery())
+          {
+              while (resultSet.next())
+              {
+                  fortunes.add(new Fortune(
+                          resultSet.getInt("id"),
+                          resultSet.getString("message")));
+              }
+          }
+      }
+    }
+
+    Collections.sort(fortunes);
 
     ListView<Fortune> listView = new ListView<Fortune>("fortunes", fortunes)
     {
@@ -47,16 +60,4 @@ public class FortunePage extends WebPage
     };
     add(listView);
   }
-
-  private void sort(List<Fortune> fortunes)
-  {
-    Collections.sort(fortunes, new Comparator<Fortune>()
-    {
-      @Override
-      public int compare(Fortune f1, Fortune f2)
-      {
-        return f1.message.compareTo(f2.message);
-      }
-    });
-  }
 }

+ 0 - 24
wicket/src/main/resources/hibernate.cfg.xml

@@ -1,24 +0,0 @@
-<!DOCTYPE hibernate-configuration PUBLIC
-        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
-        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
-<hibernate-configuration>
-    <session-factory>
-        <property name="hibernate.connection.datasource">java:comp/env/jdbc/hello_world</property>
-
-        <!-- SQL dialect -->
-        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
- 
-        <!-- Echo all executed SQL to stdout -->
-        <property name="show_sql">false</property>
-        <property name="hibernate.cache.use_query_cache">false</property>
-        <property name="hibernate.current_session_context_class">thread</property>
-
-        <!-- batch the updates for /updates
-          World object is small so we can batch many
-         -->
-        <property name="hibernate.jdbc.batch_size">500</property>
-
-        <mapping class="hellowicket.World" />
-        <mapping class="hellowicket.fortune.Fortune"/>
-    </session-factory>
-</hibernate-configuration>

+ 1 - 0
wicket/src/main/webapp/WEB-INF/web.xml

@@ -33,4 +33,5 @@
 		<filter-name>wicket.hellowicket</filter-name>
 		<url-pattern>/*</url-pattern>
 	</filter-mapping>
+
 </web-app>