Exception handling - Is there a better way? - model-view-controller

public bool AddEntity(int parentId, string description)
{
try
{
_connection.Open();
SqlCommand command = new SqlCommand("INSERT Structure (Path,Description) " +
"VALUES(" + GetPath(parentId) + ".GetDescendant(" + GetLastChildPath(parentId, 1) + ", NULL), " +
description + ")", _connection);
if (command.ExecuteNonQuery() <= 0) _success = false;
command.Connection.Close();
if (_success)
{
return true;
}
throw new Exception("An error has occured whilst trying to add a entity");
}
catch (Exception ex)
{
AddError(new ErrorModel("An error has occured whilst trying to add a entity", ErrorHelper.ErrorTypes.Critical, ex));
return false;
}
}
Is there a better way of handling the exceptions in the example above?
Thanks in advance for any help.
Clare

There's quite a few things wrong here.
a. You're using inline SQL and injecting what I can only assume to be user generated data into it. This is a security risk. Use a parameterised query.
b. You're exception handling is ok but this will leave the connection open if an error occurs. I'd write it like so:
public bool AddEntity(int parentId, string description)
{
try
{
//Assuming you have a string field called connection string
using(SqlConnection conn = new SqlConnection(_connectionString))
{
SqlParameter descriptionParam = new SqlParameter("#description", SqlDbType.VarChar, 11);
descriptionParam.Value = description;
SqlParameter parentIdParam = new SqlParameter("#parentId", SqlDbType.Int, 4);
parentIdParam.Value = parentId;
//Bit confused about the GetPath bit.
SqlCommand command = new SqlCommand("INSERT Structure (Path,Description) " +
"VALUES(" + GetPath(parentId) + ".GetDescendant(" + GetLastChildPath(parentId, 1) + ", NULL),#description)", conn);
command.Parameters.Add(descriptionParam);
if (command.ExecuteNonQuery() <= 0) _success = false;
}
if (_success)
{
return true;
}
//This isn't really an exception. You know an error has a occured handle it properly here.
throw new Exception("An error has occured whilst trying to add a entity");
}
catch (Exception ex)
{
AddError(new ErrorModel("An error has occured whilst trying to add a entity", ErrorHelper.ErrorTypes.Critical, ex));
return false;
}

You can take advantage of the IDisposable interface, and the power of a using block.
using(var connection = new Connection()) // Not sure what _connection is, in this method, so making pseudo-code
{
// ... work with connection
}
This will close the connection even if an exception is thrown. It turns into (more-or-less) this:
var connection = new Connection();
try
{
// ... work with connection
}
finally
{
connection.Dispose();
}
Dispose, in this case, will close the connection.

Related

Can't execute custom logic in finally block in try-with-resource block

Java 8
Here classic try-catch block.
FileOutputStream out = null;
try {
out = new FileOutputStream(file);
byte[] bytes = new byte[1024];
int read = 0;
int totalRead = 0;
while ((read = iStream.read(bytes)) > 0) {
// some code here
}
return totalRead;
} catch (Exception e) {
throw new IOException(fileName + " failed, got: " + e.toString(), e);
} finally {
if (out != null) {
out.getFD().sync();
out.close();
}
}
As you can see I do some custom logic in the finally block
out.getFD().sync();
Nice. It's work fine.
Now I want to replace it by try-with-resources block. I try this
try (FileOutputStream out = new FileOutputStream(file)) {
byte[] bytes = new byte[1024];
int read = 0;
int totalRead = 0;
while ((read = iStream.read(bytes)) > 0) {
// som ecode here
}
return totalRead;
} catch (Exception e) {
throw new IOException(fileName + " failed, got: " + e.toString(), e);
} finally {
if (out != null) {
out.getFD().sync();
out.close();
}
}
but get compile error in finally block:
cannot find symbol
symbol: variable out
The whole point of try-with-resources is that you do not need to call close() as the compiler ensures that it has been called. Since this happens before the finally block is executed, you can’t perform other actions on the resource in finally, like the sync call.
You can easily verify this
try(Closeable c = () -> System.out.println("close")) {
throw new IOException("stop here");
}
finally {
System.out.println("In finally block");
}
will print
close
In finally block
Exception in thread "main" java.io.IOException: stop here
If you really need to perform a sync operation at the end (in most cases: you don’t), you still don’t have to do it manually
try(OutputStream out = Files.newOutputStream(file.toPath(), StandardOpenOption.SYNC,
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
byte[] bytes = new byte[1024];
int read = 0;
int totalRead = 0;
while ((read = iStream.read(bytes)) > 0) {
// some code here
}
return totalRead;
}
I hope, your “some code” is not just a plain copying which you could simply do with Files.copy(Path, Path, …) or Files.copy(InputStream, Path, …).
You should also consider using long for totalRead…

spring security's searchForSingleEntryInternal method throws exception if record not found

I'm working on an application that uses Spring Security's searchForSingleEntryInternal method. Is there a way to do the same thing without throwing an exception if a record is not found? I want to be able to create a condition that handles missing records.
What I want to change
if (results.size() == 0) {
throw new IncorrectResultSizeDataAccessException(1, 0);
}
From this method
/**
* Internal method extracted to avoid code duplication in AD search.
*/
public static DirContextOperations searchForSingleEntryInternal(DirContext ctx, SearchControls searchControls,
String base, String filter, Object[] params) throws NamingException {
final DistinguishedName ctxBaseDn = new DistinguishedName(ctx.getNameInNamespace());
final DistinguishedName searchBaseDn = new DistinguishedName(base);
final NamingEnumeration<SearchResult> resultsEnum = ctx.search(searchBaseDn, filter, params, searchControls);
if (logger.isDebugEnabled()) {
logger.debug("Searching for entry under DN '" + ctxBaseDn + "', base = '" + searchBaseDn + "', filter = '" + filter + "'");
}
Set<DirContextOperations> results = new HashSet<DirContextOperations>();
try {
while (resultsEnum.hasMore()) {
SearchResult searchResult = resultsEnum.next();
// Work out the DN of the matched entry
DistinguishedName dn = new DistinguishedName(new CompositeName(searchResult.getName()));
if (base.length() > 0) {
dn.prepend(searchBaseDn);
}
if (logger.isDebugEnabled()) {
logger.debug("Found DN: " + dn);
}
results.add(new DirContextAdapter(searchResult.getAttributes(), dn, ctxBaseDn));
}
} catch (PartialResultException e) {
LdapUtils.closeEnumeration(resultsEnum);
logger.info("Ignoring PartialResultException");
}
if (results.size() == 0) {
throw new IncorrectResultSizeDataAccessException(1, 0);
}
if (results.size() > 1) {
throw new IncorrectResultSizeDataAccessException(1, results.size());
}
return results.iterator().next();
}
}
I'm somewhat new to spring and maybe I'm missing something obvious. Any advice would be much appreciated
easy fix, just had to copy over the searchForSingleEntryInternal method from Spring Security and place it in my own project. From there I was able to tweak the exception handling so the application didn't come to a grinding halt if a record wasn't found.

JavaFX: ConcurrentModificationException while adding TreeItem objects in TreeView, in a seperate thread

I have the following code
public void start(Stage primaryStage) {
BorderPane border_pane = new BorderPane();
TreeView tree = addTreeView(); //TreeView on the LEFT
border_pane.setLeft(tree);
/* more stuff added to the border_pane here... */
Scene scene = new Scene(border_pane, 900, 700);
scene.setFill(Color.GHOSTWHITE);
primaryStage.setTitle("PlugControl v0.1e");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
With addTreeView being a function that reads data off an SQL DB and adds around ~35 TreeItems, based on that data. The addition of TreeItems to treeItemRoot is done in a seperate thread. NOTE: treeItemRoot is declared in the main class, and is null before here.
public TreeView addTreeView() { //Our treeView is positioned on the LEFT
treeItemRoot = new PlugTreeItem<>("Active Plugs", new ImageView(new Image(getClass().getResourceAsStream("graphics/plugicon.png"))), new Plug()); //Root of the tree, contains a dummy Plug object.
selectedTreeItem = treeItemRoot;
treeItemRoot.setExpanded(true); //always expand it
selectedTreeItem.getPlugItem()
.getSIHUid().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue
) {
System.err.println("changed " + oldValue + "->" + newValue);
}
}
);
TreeView<String> treeView = new TreeView<>(treeItemRoot); //Build the tree with our root node.
final Task task;
task = new Task<Void>() {
#Override
protected Void call() throws Exception {
//=========== SQL STUFF BEGINS HERE ============================
Statement sta = null;
ResultSet result_set = null;
Connection conn = null;
try {
try {
System.err.println("Loading JDBC driver...");
Class.forName("com.mysql.jdbc.Driver");
System.err.println("Driver loaded!");
} catch (ClassNotFoundException e) {
throw new RuntimeException("Cannot find JDBC driver in the classpath!", e);
}
System.err.println("Connecting to database...");
conn = DriverManager.getConnection("[DB link here]", "[username]", "[password]"); //Username is PlugControl, pw is woof
System.err.println("Connected to Database!");
sta = conn.createStatement();
String sql_query = "SELECT * FROM pwnodes INNER JOIN pwcomports ON pwnodes.NetworkID = pwcomports.NetworkID WHERE pwnodes.connection = 'on' ORDER BY pwnodes.Location";
result_set = sta.executeQuery(sql_query);
System.err.println("SQL query successfuly executed!");
int count = 0;
while (result_set.next()) {
Plug pl = null; //MARKER: We might need to do switch (result_set.getString("Server")) for SIHU1 and SIHU2.
count++;
pl = new Plug(result_set.getString("SIHUid"), result_set.getString("sensorID"), result_set.getString("Location"), result_set.getString("Appliance"), result_set.getString("Type"), result_set.getString("connection"), result_set.getString("Server"), result_set.getString("ServerIP"));
PlugTreeItem<String> pti = new PlugTreeItem(pl.getSIHUid().getValue() + " " + pl.getLocation() + " " + pl.getAppliance(), new ImageView(new Image(getClass().getResourceAsStream("graphics/smiley.png"))), pl); //icon does not work in children
treeItemRoot.getChildren().add(pti); //CONCURRENCY ERRORS HERE
}
System.err.println("ALERT SQL QUERY RESULTS: " + count);
} catch (SQLException e) //linked try clause # line 50
{
throw new RuntimeException("Cannot connect the database!", e);
} finally { // Time to wrap things up, by closing all open SQL procs.
try {
if (sta != null) {
sta.close();
}
if (result_set != null) {
result_set.close();
}
if (conn != null) {
System.err.println("Closing the connection.");
conn.close();
}
} catch (SQLException e) //We might as well ignore this, but just in case.
{
throw new RuntimeException("Error while closing up statement, result set and connection!", e);
}
}
//============== SQL STUFF ENDS HERE ===========================
System.err.println("Finished");
return null;
}
};
new Thread(task).start(); //Run the task!
treeView.getSelectionModel()
.selectedItemProperty().addListener(new ChangeListener() {
#Override
public void changed(ObservableValue observable, Object oldValue, Object newValue
) {
selectedTreeItem = (PlugTreeItem<String>) newValue;
System.err.println("DEBUG: Selection plug SIHUid: " + selectedTreeItem.getPlugItem().print()); //MARKER: REMOVE
updateTextFields(); //Update TextAreas.
if (!"DUMMY".equals(selectedTreeItem.getPlugItem().getSIHUid().getValue())) {
buttonOn.setDisable(false);
buttonOff.setDisable(false);
} else {
buttonOn.setDisable(true);
buttonOff.setDisable(true);
}
}
}
);
return treeView;
}
Once every 5-6 runs I receive a ConcurrentModificationException because I think the Thread task() doesn't manage to finish before addTreeView's returned TreeView is added to the border_pane, and maybe it begins iterating through it while it's still having items added to it?
Executing C:\Users\74\Documents\NetBeansProjects\PlugControl_v0.5\dist\run1559674105\PlugControl.jar using platform C:\Program Files\Java\jdk1.7.0_25\jre/bin/java
Loading JDBC driver...
Driver loaded!
Connecting to database...
Connected to Database!
SQL query successfuly executed!
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
at java.util.ArrayList$Itr.next(ArrayList.java:791)
at com.sun.javafx.collections.ObservableListWrapper$ObservableListIterator.next(ObservableListWrapper.java:681)
at javafx.scene.control.TreeItem.updateExpandedDescendentCount(TreeItem.java:788)
at javafx.scene.control.TreeItem.getExpandedDescendentCount(TreeItem.java:777)
at javafx.scene.control.TreeView.getExpandedDescendantCount(TreeView.java:864)
at javafx.scene.control.TreeView.updateTreeItemCount(TreeView.java:873)
at javafx.scene.control.TreeView.impl_getTreeItemCount(TreeView.java:533)
at com.sun.javafx.scene.control.skin.TreeViewSkin.getItemCount(TreeViewSkin.java:207)
at com.sun.javafx.scene.control.skin.TreeViewSkin.updateItemCount(TreeViewSkin.java:220)
at com.sun.javafx.scene.control.skin.TreeViewSkin.handleControlPropertyChanged(TreeViewSkin.java:135)
at com.sun.javafx.scene.control.skin.SkinBase$3.changed(SkinBase.java:282)
at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:107)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:196)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)
at javafx.beans.property.IntegerPropertyBase.fireValueChangedEvent(IntegerPropertyBase.java:123)
at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:130)
at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:163)
at javafx.scene.control.TreeView.setTreeItemCount(TreeView.java:515)
at javafx.scene.control.TreeView.updateTreeItemCount(TreeView.java:876)
at javafx.scene.control.TreeView.impl_getTreeItemCount(TreeView.java:533)
at javafx.scene.control.TreeCell.updateItem(TreeCell.java:391)
at javafx.scene.control.TreeCell.access$000(TreeCell.java:67)
at javafx.scene.control.TreeCell$1.invalidated(TreeCell.java:95)
at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:155)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)
at javafx.beans.property.ReadOnlyIntegerWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:195)
at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:161)
at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:130)
at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:163)
at javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:112)
at com.sun.javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1596)
at com.sun.javafx.scene.control.skin.VirtualFlow.addLeadingCells(VirtualFlow.java:1049)
at com.sun.javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1005)
at com.sun.javafx.scene.control.skin.VirtualFlow.setCellCount(VirtualFlow.java:206)
at com.sun.javafx.scene.control.skin.TreeViewSkin.updateItemCount(TreeViewSkin.java:225)
at com.sun.javafx.scene.control.skin.TreeViewSkin.handleControlPropertyChanged(TreeViewSkin.java:135)
at com.sun.javafx.scene.control.skin.SkinBase$3.changed(SkinBase.java:282)
at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:107)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:196)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)
at javafx.beans.property.IntegerPropertyBase.fireValueChangedEvent(IntegerPropertyBase.java:123)
at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:130)
at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:163)
at javafx.scene.control.TreeView.setTreeItemCount(TreeView.java:515)
at javafx.scene.control.TreeView.updateTreeItemCount(TreeView.java:876)
at javafx.scene.control.TreeView.impl_getTreeItemCount(TreeView.java:533)
at javafx.scene.control.TreeCell.updateItem(TreeCell.java:391)
at javafx.scene.control.TreeCell.access$000(TreeCell.java:67)
at javafx.scene.control.TreeCell$1.invalidated(TreeCell.java:95)
at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:155)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)
at javafx.beans.property.ReadOnlyIntegerWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:195)
at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:161)
at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:130)
at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:163)
at javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:112)
at com.sun.javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1596)
at com.sun.javafx.scene.control.skin.VirtualFlow.getCell(VirtualFlow.java:1500)
at com.sun.javafx.scene.control.skin.VirtualFlow.getCellLength(VirtualFlow.java:1523)
at com.sun.javafx.scene.control.skin.VirtualFlow$3.call(VirtualFlow.java:478)
at com.sun.javafx.scene.control.skin.VirtualFlow$3.call(VirtualFlow.java:476)
at com.sun.javafx.scene.control.skin.PositionMapper.computeViewportOffset(PositionMapper.java:143)
at com.sun.javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1001)
at javafx.scene.Parent.layout(Parent.java:1018)
at javafx.scene.Parent.layout(Parent.java:1028)
at javafx.scene.Parent.layout(Parent.java:1028)
at javafx.scene.Parent.layout(Parent.java:1028)
at javafx.scene.Scene.layoutDirtyRoots(Scene.java:516)
at javafx.scene.Scene.doLayoutPass(Scene.java:487)
at javafx.scene.Scene.access$3900(Scene.java:170)
at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2203)
at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:363)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:460)
at com.sun.javafx.tk.quantum.QuantumToolkit$9.run(QuantumToolkit.java:329)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:29)
at com.sun.glass.ui.win.WinApplication$3$1.run(WinApplication.java:73)
at java.lang.Thread.run(Thread.java:724)
ALERT SQL QUERY RESULTS: 35
Closing the connection.
Finished
Any help/advice on dealing with the issue, guys? The exception doesn't point me towards a place in my code, and so far I'm working on hunches.}
EDIT: For reference, PlugTreeItem is just a TreeItem<> that also carries a Plug with it, Plug being a class of mine that holds a few String values. Nothing special.
public class PlugTreeItem<T> extends TreeItem{ \* code *\}
I would suggest you to make a List<Plug> inside your while loop rather than making individual object and adding it to the tree, because all operations on javafx controls must be done on javafx thread and not on task thread !
Create a list outside the Thread body
List<Plug> listOfPlugs = new ArrayList<Plug>();
Then, in the while loop, you can write
int count = 0;
while (result_set.next()) {
Plug pl = null;
count++;
pl = new Plug(result_set.getString("SIHUid"),
result_set.getString("sensorID"), result_set.getString("Location"),
result_set.getString("Appliance"), result_set.getString("Type"),
result_set.getString("connection"), result_set.getString("Server"),
result_set.getString("ServerIP"));
listOfPlugs.add(p1);
}
Later, after you start the thread you can make the following code
new Thread(task).start();
task.setOnSucceeded(new EventHandler<WorkerStateEvent>()
{
#Override
public void handle(WorkerStateEvent workerStateEvent) {
for(Plug p1 : listOfPlugs)
{
PlugTreeItem<String> pti = new PlugTreeItem(pl.getSIHUid().getValue()
+ " " + pl.getLocation() + " " + pl.getAppliance(),
new ImageView(new Image(
getClass().getResourceAsStream("graphics/smiley.png"))), pl);
treeItemRoot.getChildren().add(pti);
}
}
I don't see you syncing on the javafx application thread which is required when coming from another one

How to call Oracle function from Hibernate3 [duplicate]

My question is very much like Getting the return value of a PL/SQL function via Hibernate
I have a function which does some modifications internally and it returns a value.
The original idea was to do something like this:
protected Integer checkXXX(Long id, Long transId)
throws Exception {
final String sql = "SELECT MYSCHEMA.MYFUNC(" + id + ", "
+ transId + ") FROM DUAL";
final BigDecimal nr = (BigDecimal) this.getHibernateTemplate()
.getSessionFactory().getCurrentSession().createSQLQuery(sql)
.uniqueResult();
return nr.intValue();
}
Unfortunately this doesn't work with Oracle. What is the recommended way to do something like this?
Is there a way to extract declared variables from within my statement?
Hibernate Session provides a doWork() method that gives you direct access to java.sql.Connection. You can then create and use java.sql.CallableStatement to execute your function:
session.doWork(new Work() {
public void execute(Connection connection) throws SQLException {
CallableStatement call = connection.prepareCall("{ ? = call MYSCHEMA.MYFUNC(?,?) }");
call.registerOutParameter( 1, Types.INTEGER ); // or whatever it is
call.setLong(2, id);
call.setLong(3, transId);
call.execute();
int result = call.getInt(1); // propagate this back to enclosing class
}
});
You have the following options:
With a #NamedNativeQuery:
#org.hibernate.annotations.NamedNativeQuery(
name = "fn_my_func",
query = "{ ? = call MYSCHEMA.MYFUNC(?, ?) }",
callable = true,
resultClass = Integer.class
)
Integer result = (Integer) entityManager.createNamedQuery("fn_my_func")
.setParameter(1, 1)
.setParameter(2, 1)
.getSingleResult();
With JDBC API:
Session session = entityManager.unwrap( Session.class );
final AtomicReference<Integer> result =
new AtomicReference<>();
session.doWork( connection -> {
try (CallableStatement function = connection
.prepareCall(
"{ ? = call MYSCHEMA.MYFUNC(?, ?) }"
)
) {
function.registerOutParameter( 1, Types.INTEGER );
function.setInt( 2, 1 );
function.setInt( 3, 1 );
function.execute();
result.set( function.getInt( 1 ) );
}
} );
With a native Oracle query:
Integer result = (Integer) entityManager.createNativeQuery(
"SELECT MYSCHEMA.MYFUNC(:postId, :transId) FROM DUAL")
.setParameter("postId", 1)
.setParameter("transId", 1)
.getSingleResult();
Yes, you do need to use an out parameter. If you use the doWork() method, you'd do something like this:
session.doWork(new Work() {
public void execute(Connection conn) {
CallableStatement stmt = conn.prepareCall("? = call <some function name>(?)");
stmt.registerOutParameter(1, OracleTypes.INTEGER);
stmt.setInt(2, <some value>);
stmt.execute();
Integer outputValue = stmt.getInt(1);
// And then you'd do something with this outputValue
}
});
Alternative code :)
if you want to direct result you can use below code
int result = session.doReturningWork(new ReturningWork<Integer>() {
#Override
public Integer execute(Connection connection) throws SQLException {
CallableStatement call = connection.prepareCall("{ ? = call MYSCHEMA.MYFUNC(?,?) }");
call.registerOutParameter( 1, Types.INTEGER ); // or whatever it is
call.setLong(2, id);
call.setLong(3, transId);
call.execute();
return call.getInt(1); // propagate this back to enclosing class
}
});
http://keyurj.blogspot.com.tr/2012/12/dowork-in-hibernate.html
public static void getThroHibConnTest() throws Exception {
logger.debug("UsersActiion.getThroHibConnTest() | BEG ");
Transaction tx = null;
Connection conn = null;
CallableStatement cs = null;
Session session = HibernateUtil.getInstance().getCurrentSession();
try {
tx = session.beginTransaction();
conn = session.connection();
System.out.println("Connection = "+conn);
if (cs == null)
{
cs =
conn.prepareCall("{ ?=call P_TEST.FN_GETSUM(?,?) }");
}
cs.clearParameters();
cs.registerOutParameter(1,OracleTypes.INTEGER);
cs.setInt(2,1);
cs.setInt(3,2);
cs.execute();
int retInt=cs.getInt(1);
tx.commit();
}catch (Exception ex) {
logger.error("UsersActiion.getThroHibConnTest() | ERROR | " , ex);
if (tx != null && tx.isActive()) {
try {
// Second try catch as the rollback could fail as well
tx.rollback();
} catch (HibernateException e1) {
logger.debug("Error rolling back transaction");
}
// throw again the first exception
throw ex;
}
}finally{
try {
if (cs != null) {
cs.close();
cs = null;
}
if(conn!=null)conn.close();
} catch (Exception ex){;}
}
logger.debug("UsersActiion.getThroHibConnTest() | END ");
}

C3P0 Statement.close deadlock

Google returns lots of people with deadlock issues in C3P0, but none of the solutions appear to apply (most people suggest setting maxStatements = 0 and maxStatementsPerConnection = 0, both of which we have).
I am using a ComboPooledDataSource from C3P0, initialised as;
cpds = new ComboPooledDataSource();
cpds.setDriverClass("org.postgresql.Driver");
cpds.setJdbcUrl("jdbc:postgresql://" + host + ":5432/" + database);
cpds.setUser(user);
cpds.setPassword(pass);
My query function looks like;
public static List<Map<String, Object>> query(String q) {
Connection c = null;
Statement s = null;
ResultSet r = null;
try {
c = cpds.getConnection();
s = c.createStatement();
s.executeQuery(q);
r = s.getResultSet();
/* parse result set into results List<Map> */
return results;
}
catch(Exception e) { MyUtils.logException(e); }
finally {
closeQuietly(r);
closeQuietly(s);
closeQuietly(c);
}
return null;
}
No queries are returning, despite the query() method reaching the return results; line. The issue is that the finally block is hanging. I have determined that the closeQuietly(s); is the line that is hanging indefinitely.
The closeQuietly() method in question is as you would expect;
public static void closeQuietly(Statement s) {
try { if(s != null) s.close(); }
catch(Exception e) { MyUtils.logException(e); }
}
Why would this method hang on s.close()? I guess it is something to do with the way I am using C3P0.
My complete C3P0 configuration (almost entirely defaults) can be viewed here -> http://pastebin.com/K8XDdiBg
MyUtils.logException(); looks something like;
public static void logException(Exception e) {
StackTraceElement ste[] = e.getStackTrace();
String message = " !ERROR!: ";
for(int i = 0; i < ste.length; i++) {
if(ste[i].getClassName().contains("packagename")) {
message += String.format("%s at %s:%d", e.toString(), ste[i].getFileName(), ste[i].getLineNumber());
break;
}
}
System.err.println(message);
}
Everything runs smoothly if I remove the closeQuietly(s); line. Both closing the ResultSet and Connection object work without problem - apart from Connection starvation of course.

Resources