I am pretty sure that this is a silly question, but I am totally confused here. I am used to code with neo4j-embedded-api and very new to neo4j-jdbc. I want to use Neo4j-JDBC. My Neo4J 2.1.7 instance is hosted on another computer which is accessible via 192.168.1.16:7474
I can create simple programs and write cypher queries and execute them. However, I would like to wrap all of them in a transactional block. Something like this:
try(Transaction tx = this.graphDatabaseService.beginTx())
{
ResultSet resultSet = connect.createStatement().executeQuery(cypherQuery);
tx.success();
}
My issue is that I do not know how to get the object of GraphDatabaseService from this:
Neo4jConnection connect = new Driver().connect("jdbc:neo4j://192.168.1.16:7474", new Properties());
Once I have the GraphDatabaseObject, I am assuming that I can use the transactional block like neo4j-embedded-api.
[My Objective]
What I am trying to attempt here is to have multiple queries to be sent over the network in a nested-transaction block and if any one of them fails, to rollback all of them.
My failed attempts till now:
I tried to read the neo4j-jdbc project hosted on github and from their test case (link here) I am assuming that to put a code in transaction block you have to connect.setAutoCommit(false); and then use commit() and rollback() functions respectively.
If you don't know JDBC then please read up on it, it's a remote API which works by executing statement (Cypher in this case) against a remote API.
There is no GraphDatabaseService object. Only statements and parameters.
For tx handling you either have one tx per statement or if you set connection.setAutoCommit(false); then the transaction runs until you call connection.commit()
Just to add to Michael Hunger's answer, I made this program which does multiple transactions and rolls back them. This is a very easy program. Hope it helps other noobies like me.
package rash.experiments.neo4j.jdbc;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import org.neo4j.jdbc.Driver;
import org.neo4j.jdbc.Neo4jConnection;
public class JdbcTest
{
public Neo4jConnection connect;
public JdbcTest() throws SQLException
{
this.connect = new Driver().connect("jdbc:neo4j://192.168.1.16:7474", new Properties());
}
public static void main(String args[])
{
JdbcTest test = null;
try
{
test = new JdbcTest();
test.connect.setAutoCommit(false);
long user1 = test.createUser("rash");
long user2 = test.createUser("honey");
test.createRelationship(user1, user2);
test.connect.commit();
}
catch(SQLException sqlException)
{
try
{
test.connect.rollback();
}
catch (SQLException e){}
}
}
private long createUser(String userId) throws SQLException
{
ResultSet resultSet = this.connect.createStatement().executeQuery("create (user:User {userId: '" + userId + "'}) return id(user) as id");
resultSet.next();
return resultSet.getLong("id");
}
private void createRelationship(long node1, long node2) throws SQLException
{
this.connect.createStatement().executeQuery("start user1 = node(" + node1 + "), user2 = node(" + node2 + ") create (user1) -[:KNOWS]-> (user2)");
throw new SQLException();
}
}
This program will never commit because method createRelationship() throws an error and the program never gets a chance to commit. Instead it rolls back.
Related
I don't understand why my code acts a curtain way so it would be awesome if someone could explain. The problem I am facing... I have 2 tables. As soon the method starts I insert something in "table1", after the inserting I start the transaction. Let's assume that code flow will always reach transaction.rollback(). I expect for the second query to be rollbacked, but not the first one. But it seems to me that both of them are rollbacked.
TLDR;
Expected result:
First query is commited
Second query is rollbacked
Current outcome:
First query is rollbacked
Second query is rollbacked
//Relevant imports
import java.sql.PreparedStatement;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.jdbc.Work;
public boolean myMethod(String createdBy) {
final Long messageId = ((BigInteger) myEntityManager.createNativeQuery("insert into table1(created_by) values (:createdBy) returning id")
.setParameter("createdBy", createdBy)
.getSingleResult()).longValue();
Session session = myEntityManager.unwrap(Session.class);
Transaction tx = session.beginTransaction();
session.doWork(new Work() {
#Override
public void execute(Connection conn) throws SQLException {
String sqlInsert = "insert into table2(messageId) values (?)";
try ( PreparedStatement pstmt = conn.prepareStatement(sqlInsert)) {
for (Object[] row : unsentRecords) {
pstmt.setLong(1, messageId);
pstmt.addBatch();
}
//Execute batch
int[] sqlStatmentsStatuses = pstmt.executeBatch();
//check if some statement failed
//Let's assume it always fails,just to be explicit
boolean somethingWentWrong = atLeastOneFailed(sqlStatmentsStatuses);
somethingWentWrong = true;
if(somethingWentWrong){
tx.rollback();
}
}
}
}
}
NOTE: I don't know how to accurately call this question. So if someone can suggest a better title for the question put it in the comment and I will change it.
Below is Transaction#beginTransaction javadoc
Begin a unit of work and return the associated Transaction object. If a new underlying transaction is required, begin the transaction. Otherwise continue the new work in the context of the existing underlying transaction.
It says create begin new transaction if not available. In you case, you are already executing one query which is starting transaction. So when you say session.beginTransaction(), it's not creating new transaction but returning existing transaction and that's why when you do rollback on that transaction, both queries are getting rolled back.
I need to use a connection pool in a standalone (as in non-web) Java application. Where I work, we are not allowed to use APIs without going through layers of security, and the job needs to be completed soon. Below is my attempt at creating this connection pool.
I have unit tested this code and tested it within the context of the overall application a hundred times and in all cases the tests passed with zero errors, and in addition the performance of each run is just under three thousand times faster than a simple connect, retrieve data, disconnect in serial approach; however, I still have nagging concerns that there could be issues with this approach that I simply haven't unearthed yet. I would appreciate any advice anyone has concerning the below code. This is my first post on this site; please let me know if I've made any errors in etiquette. I did search this site about this problem before posting. Please see below the code for an invocation example. Thanks. --JR
package mypackage;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* Note: This class is only instantiated once per application run.
* Multiple instantiations, as specified in the release notes,
* are not supported.
*/
public class ConnectionManager {
// Use a blocking queue to store the database connections.
// The application will only be called once, by a single user,
// but within the application many threads will require
// a connection.
private BlockingQueue<Connection> connectionQueue = null;
// Load the connection queue with a user-defined number of connections.
// Params contains a map of all non hard-coded variables in the
// application.
public ConnectionManager(int howMany, Map<String, Object> params) {
Database database = new Database();
connectionQueue = new ArrayBlockingQueue<Connection>(howMany);
for(int i = 0; i < howMany; i++) {
connectionQueue.add(database.getConn(params));
}
}
// Return a connection from the queue, waiting up to 15 minutes to do so.
// 15 minutes is hard-coded because it is the standard time-out for all
// processes at our agency. This application must complete in less
// than fifteen minutes (is currently completing in thirty five seconds).
public Connection getConnection() {
Connection conn = null;
try {
conn = connectionQueue.poll(15, TimeUnit.MINUTES);
}
catch(InterruptedException e) {
e.printStackTrace();
}
catch(SQLException e) {
e.printStackTrace();
}
return conn;
}
// Returns a connection to the connection queue.
public void returnConnectionToManager(Connection conn) {
connectionQueue.add(conn);
}
// Called on the last line of the application program's dispatcher.
// Closes all active connections (which will only exist if there
// was a failure within one of the worker threads).
public void closeAllConnections() {
for(Connection conn : connectionQueue) {
try {
conn.close();
}
catch(SQLException e) {
e.printStackTrace();
}
}
}
}
Invocation example:
...
private ConnectionManager cm;
...
public Table(Map<String, Object> params, String method) {
...
cm = (ConnectionManager) params.get("cm");
}
// Execute a chunk of SQL code without requiring processing of a
// result set. Acquires connection from pool via cm.getConnection
// and releases connection via cm.returnConnectionToManager.
// (Database is just a helper class with simple methods for
// closing prepared statement, result sets, etc.)
private void execute(String sql) {
PreparedStatement ps = null;
Connection conn = null;
try {
conn = cm.getConnection();
ps = conn.prepareStatement(sql);
ps.execute();
}
catch (SQLException e) {
e.printStackTrace();
}
finally {
database.closePreparedStatement(ps);
cm.returnConnectionToManager(conn);
}
}
Your code looks good, but there is one serious problem, that clients of your API needs to take care of getting and releasing connection, one of them forget, and memory/resource leak is ready.
Make a one place in which you posts your queries to execute, in this place take connection, execute query and return the connection to the pool. It will secure you that the connections are returned. If you need to invoke multiple queries one after another in a single connection make the method accept an array or list of SQL queries to execute in order. The idea is to encapsulate each request to the db, so you manage all connections. It could be donethat you write an interface that has en execute(Connection conn) which you need to implement, and you could have then some Service that takes such object gives it a connection and then releases the resources back to connection pool.
Something like:
interface SqlWork {
execute(Connection conn);
}
SqlWork myWork = new SqlWork () {
execute(Connection conn) {
// do you work with the conn here
}
}
class SqlExecutionService {
ConnectionManager cm = ...;
public void execute(SqlWork sqlWork) {
Connection conn = null;
try {
conn = cm.getConnection();
sqlWork.execute(conn);
} catch (Your exceptions here) {
//serve or rethrow them
}
finally
{
if (conn!=null) {
cm.returnConnectionToManager(conn);
}
}
}
}
Example of use:
SqlExecutionService sqlExecService = ...;
sqlExecService.execute(myWork);
I am just getting started with jsp and my question is this - when I have a singleton class, how do I tidy up after it?
In particular:
public class DBConnection {
private static Connection connection = null;
private static Statement statement = null;
public static ResultSet executeQuery(String query){
if (connection == null) { /*initConnection*/ }
if (statement == null) { /*initStatement*/ }
// do some stuff
}
}
Now, I use this class in several pages to get results from jdbc. However, I need to eventually call statement.close(); and connection.close(); - when should I call those?
I am using singleton, because it felt wrong to call for connection to a database over and over whenever I needed to make a query.
The Connection must be closed always, and after you have executed all your database statements for the desired operations. Two examples:
Case 1: You must show a list of products to user filtered by criteria from database. Solution: get a connection, retrieve a list of products using the filter criteria, close the connection.
Case 2: The client selects some of these products and updates the minimum stock to get an alert and restock them. Solution: get a connection, update all the products, close the connection.
Based on these cases, we can learn lot of things:
You can execute more than a single statement while having/maintaining a single connection open.
The connection should live only in the block where it is used. It should not live before or after that.
Both cases can happen at the same time since they are in a multi threaded environment. So, a single database connection must not be available to be used by two threads at the same time, in order to avoid result problems. For example, user A searches the products that are in category Foo and user B searches the products that are in category Bar, you don't want to show the products in category Bar to user A.
From last sentence, each database operation ((or group of similar operations like Case 2) should be handled in an atomic operation. To assure this, the connection must not be stored in a singleton object, instead it must be live only in the method being used.
In consequence:
Do not declare the Connection nor the Statement nor the ResultSet nor other JDBC resource as static. It will simply fail. Instead, declare only the Connection as field of your DBConnection class. Let each method decide to handle each Statement (or PreparedStatement) and ResultSet and specific JDBC resources.
Since you must close the connection after its usage, then add two more methods: void open() and void close(). These methods will handle the database connection retrieval and closing that connection.
Additional, since the DBConnection looks like a wrapper class for Connection class and database connection operations, I would recommend to have at least three more methods: void setAutoCommit(boolean autoCommit), void commit() and void rollback(). These methods will be plain wrappers for Connection#setAutoCommit Connection#close and Connection#rollback respectively.
Then you can use the class in this way:
public List<Product> getProducts(String categoryName) {
String sql = "SELECT id, name FROM Product WHERE categoryName = ?";
List<Product> productList = new ArrayList<Product>();
DBConnection dbConnection = new DBConnection();
try {
dbConnection.open();
ResultSet resultSet = dbConnection.executeSelect(sql, categoryName); //execute select and apply parameters
//fill productList...
} catch (Exception e) {
//always handle your exceptions
...
} finally {
//don't forget to also close other resources here like ResultSet...
//always close the connection
dbConnection.close();
}
}
Note that in this example the PreparedStatement is not in the getProducts method, it will be a local variable of the executeSelect method.
Additional notes:
When working in an application server, you should not open connections naively e.g. using Class.forName("..."), instead use a database connection pool. You can roll on some database connection pooling libraries like C3P0 as explained here: How to establish a connection pool in JDBC?. Or configure one in your application server, as I explain here: Is it a good idea to put jdbc connection code in servlet class?
If this is for learning purposes, then roll on your own classes to handle the communication with your database. In real world applications, this is not recommended (doesn't mean you should not do it). Instead, use a database connectivity framework like ORMs e.g. JPA (Java official ORM framework) or Hibernate; there are no ORM frameworks that handles database communication like Spring JDBC and MyBatis. The choice is yours.
More info:
Should a database connection stay open all the time or only be opened when needed?
How do servlets work? Instantiation, sessions, shared variables and multithreading. Not directly related to your question, but it will help you understand why to not maintain state in resources that are used in multithreaded environments.
Define connection resource in mywebapp/META-INF/context.xml file
<Resource name="jdbc/mydb" auth="Container" type="javax.sql.DataSource"
maxActive="10" maxIdle="2" maxWait="20000"
driverClassName="com.mysql.jdbc.Driver"
username="myuser" password="mypwd"
url="jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8"
validationQuery="SELECT 1" />
Create DB.java helper class to minimize code in other parts of app
import java.sql.*;
import javax.sql.DataSource;
import javax.naming.Context;
import javax.naming.InitialContext;
public class DB {
public static Connection createConnection() throws SQLException {
try {
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/mydb");
return ds.getConnection();
} catch (SQLException ex) {
throw ex;
} catch (Exception ex) {
SQLException sqex = new SQLException(ex.getMessage());
sqex.initCause(ex);
throw sqex;
}
}
public static void close(ResultSet rs, Statement stmt, Connection conn) {
if (rs != null) try { rs.close(); } catch (Exception e) { }
if (stmt != null) try { stmt.close(); } catch (Exception e) { }
if (conn != null) try { conn.close(); } catch (Exception e) { }
}
public static void close(ResultSet rs, boolean closeStmtAndConn) {
if (rs==null) return;
try {
Statement stmt = rs.getStatement();
close(rs, stmt, stmt!=null ? stmt.getConnection() : null);
} catch (Exception ex) { }
}
}
And somewhere in your app DAO code use DB helper.
public List<MyBean> getBeans() throws SQLException {
List<MyBean> list = new ArrayList<MyBean>();
ResultSet rs=null;
try {
Connection con = DB.createConnection();
String sql = "Select * from beantable where typeid=?";
PreparedStatement stmt = con.prepareStatement(sql, Statement.NO_GENERATED_KEYS);
stmt.setInt(1, 101);
rs = stmt.executeQuery();
while(rs.next()
list.add( createBean(rs) );
} finally {
DB.close(rs, true); // or DB.close(rs, stmt, conn);
}
return list;
}
private MyBean createBean(ResultSet rs) throws SQLException {
MyBean bean = new MyBean();
bean.setId( rs.getLong("id") );
bean.setName( rs.getString("name" );
bean.setTypeId( rs.getInt("typeid") );
return bean;
}
I would add two methods to the class:
public static void open() throws SomeException;
public static void close() throws SomeException;
then your calling code looks something like this{
try {
DBConnection.open();
... code to use the connection one or more times ...
} finally {
DBConnection.close();
}
Wrap all your database calls inside that and it will take care of closing whether there is an exception thrown or not.
Of course, this isn't much different than having a regular class, which I might recommend:
try {
DBConnection conn = new DBConnection();
conn.open();
... all the code to use the database (but you pass 'conn' around) ...
} finally {
conn.close();
}
And you might want to look at the java.lang.AutoCloseable and java.io.Closeable to see if that helps you.
2
If you are keeping it open across page loads, there isn't any place to put the try ... finally stuff so you can open it and close it when the servlet closes or the server closes or something like that.
If you are going to leave it open, you need to make sure and add code to verify it doesn't close when you aren't looking. A short network glitch, for example, could close it down. In that case, you need to reopen it when it gets closed. Otherwise, all database access from that point will fail.
You might want to look into the concept of a DataBase Pool. Apache has one -- DBCP. Tomcat has its own that's quite good. Other containers, like JBOSS, WebSphere, WebLogic all have them. There's a couple that can be used with the Spring Framework. What it does is manage one or more database connections. Your code asks it for one and it returns an open one, unless none is available and then it opens one and returns it. You call close when your code gets through with it but it doesn't really close the connection, it just returns it to the pool.
You can usually configure the pool to check for shut down connections and reopen if needed.
I've been doing my homework and I decided to re-write my vote4cash class which manages the mysql for my vote4cash reward system into a new class called MysqlManager. The MysqlManager class I've made needs to allow the Commands class to connect to mysql - done and it needs to allow the Commands class to execute a query - I need help with this part. I've had a lot more progress with the new class that I've made but I'm stuck on one of the last, most important parts of the class, again, allowing the commands class to execute a query.
In my MysqlManager class I have put the code to connects to MySql under
public synchronized static void createConnection() {
Now I just need to put the code that allows the Commands class to execute a query under this as well. I've researched and tried to do this for a while now, but I've had absolutely no luck.
The entire MysqlManager class:
package server.util;
/*
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
*/
import java.sql.*;
import java.net.*;
import server.model.players.Client;//Will be needed eventually so that I can reward players who have voted.
/**
* MySQL and Vote4Cash Manager
* #author Cloudnine
*
*/
public class MysqlManager {
/** MySQL Connection */
public static Connection conn = null;
public static Statement statement = null;
public static ResultSet results = null;
public static Statement stmt = null;
public static ResultSet auth = null;
public static ResultSet given = null;
/** MySQL Database Info */
public static String DB = "vote4gold";
public static String URL = "localhost";
public static String USER = "root";
public static String PASS = "";
public static String driver = "com.mysql.jdbc.Driver"; //Driver for JBDC(Java and MySQL connector)
/** Connects to MySQL Database*/
public synchronized static void createConnection() {
try {
Class.forName(driver);
conn = DriverManager.getConnection(URL + DB, USER, PASS);
conn.setAutoCommit(false);
stmt = conn.createStatement();
Misc.println("Connected to MySQL Database");
}
catch(Exception e) {
//e.printStackTrace();
}
}
public synchronized static void destroyConnection() {
try {
statement.close();
conn.close();
} catch (Exception e) {
//e.printStackTrace();
}
}
public synchronized static ResultSet query(String s) throws SQLException {
try {
if (s.toLowerCase().startsWith("select")) {
ResultSet rs = statement.executeQuery(s);
return rs;
} else {
statement.executeUpdate(s);
}
return null;
} catch (Exception e) {
destroyConnection();
createConnection();
//e.printStackTrace();
}
return null;
}
}
The snippet of my command:
if (playerCommand.equals("claimreward")) {
try {
PreparedStatement ps = DriverManager.getConnection().createStatement("SELECT * FROM votes WHERE ip = hello AND given = '1' LIMIT 1");
//ps.setString(1, c.playerName);
ResultSet results = ps.executeQuery();
if(results.next()) {
c.sendMessage("You have already been given your voting reward.");
} else {
ps.close();
ps = DriverManager.getConnection().createStatement("SELECT * FROM votes WHERE ip = hello AND given = '0' LIMIT 1");
//ps.setString(1, playerCommand.substring(5));
results = ps.executeQuery();
if(results.next()) {
ps.close();
ps = DriverManager.getConnection().createStatement("UPDATE votes SET given = '1' WHERE ip = hello");
//ps.setString(1, playerCommand.substring(5));
ps.executeUpdate();
c.getItems().addItem(995, 5000000);
c.sendMessage("Thank you for voting! You've recieved 5m gold!");
} else {
c.sendMessage("You haven't voted yet. Vote for 5m gold!");
}
}
ps.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return;
How the command works:
When a player types ::commandname(in this case, claimreward), the commands function will be executed. This isn't the entire commands class, just the part that I feel is needed to be posted for my question to be detailed enough for a helpful answer.
Note: I have all my imports.
Note: Mysql connects successfully.
Note: I need to make the above command code snippet able to execute mysql queries.
Note: I prefer the query to be executed straight from the command, instead of from the MysqlManager, but I will do whatever I need to resolve this problem.
I feel that I've described my problem detailed and relevantly enough, but if you need additional information or understanding on anything, tell me and I'll try to be more specific.
Thank you for taking the time to examine my problem. Thanks in advance if you are able to help.
-Alex
Your approach is misguided on many different levels, I can't even start to realize what should be done how here.
1) Don't ever use static class variables unless you know what you do there (and I'm certain, you don't)
2) I assume there is a reason you create your own jdbc connection (e.G. its part of your homework) if not, you shouldn't do that. I see you use DriverManager and PreparedStatement in one part, you should continue to use them.
3) Your approach seems to intend to start with a relative good code base (your command part) and then goes to a very low-level crude approach on database connections (your MysqlManager) unless really necessary and you know what you do, you should stay on the same level of abstraction and aim for the most abstract that fits your needs. (In this case, write MysqlManager the way you wrote Command)
4) In your previous question (that you just assumed everybody here has read, which is not the case) you got the suggestion to redesign your ideas, you should do that. Really, take a class in coding principles learn about anti-patterns and then start from scratch.
So in conclusion: Write at least the MysqlManager again, its fatally broken beyond repair. I'm sorry. Write me an email if you have further questions, I will take my time to see how I can help you. (an#steamnet.de)
Is it possible to store a database connection as a separate class, then call the database objects from a main code? ie;
public class main{
public static void main{
try{
Class.forName("com.jdbc.driver");
Database to = new Database(1,"SERVER1","DATABASE");
Database from = new Database(2,"SERVER2","DATABASE");
String QueryStr = String.format("SELECT * FROM TABLE WHERE Id = %i", to.id)
to.results = sql.executeQuery(QueryStr);
while (to.results.next()) {
String QueryStr = String.format("INSERT INTO Table (A,B) VALUES (%s,%s)",to.results.getString(1),to.results.getString(2));
from.sql.executeQuery("QueryStr");
}
to.connection.close()
from.connection.close()
} catch (Exception ex) {
ex.printStackTrace();
{ finally {
if (to.connection != null)
try {
to.connection.close();
} catch (SQLException x) {
}
if (from.connection != null)
try {
from.connection.close();
} catch (SQLException x) {
}
}
}
public static class Database {
public int id;
public String server;
public String database;
public Connection connection;
public ResultSet results;
public Statement sql;
public Database(int _id, String _server, String _database) {
id = _id;
server = _server;
database = _database;
String connectStr = String.format("jdbc:driver://SERVER=%s;port=6322;DATABASE=%s",server,database);
connection = DriverManager.getConnection(connectStr);
sql = connection.createStatement;
}
}
}
I keep getting a "Connection object is closed" error when I call to.results = sql.executeQuery("SELECT * FROM TABLE"); like the connection closes as soon as the Database is done initializing.
The reason I ask is I have multiple databases that are all about the same that I am dumping into a master database. I thought it would be nice to setup a loop to go through each from database and insert into each to database using the same class. Is this not possible? Database will also contain more methods than shown as well. I am pretty new to java, so hopefully this makes sense...
Also, my code is probably riddled with syntax errors as is, so try not to focus on that.
Connection object is closed doesn't mean that the connection is closed, but that the object relative to the connection is closed (it could be a Statement or a ResultSet).
It's difficult to see from your example, since it has been trimmed/re-arranged, but it looks like you may be trying to use a ResultSet after having re-used its corresponding Statement. See the documentation:
By default, only one ResultSet object per Statement object can be open
at the same time. Therefore, if the reading of one ResultSet object is
interleaved with the reading of another, each must have been generated
by different Statement objects. All execution methods in the Statement
interface implicitly close a statment's current ResultSet object if an
open one exists.
In your example, it may be because autoCommit is set to true by default. You can override this on the java.sql.Connection class. Better yet is to use a transaction framework if you're updating multiple tables.