I am trying to create a simple app with a SQLite database. I chose to use the SQLiteJDBC driver.
The code below is taken from the above website.
My question is about the line after public static void main...
It reads: Class.forName("org.sqlite.JDBC");
My question is, what does this line mean? And what does it do? It doesn't seem to be connected to the rest of the code. Class.forName() should return a class, but the line seems to stand alone inside the body. Whatever it returns isn't used by another part of the code, that I can see.
Please help clarify this. Thanks in advance.
public class Test {
public static void main(String[] args) throws Exception {
Class.forName("org.sqlite.JDBC");
Connection conn =
DriverManager.getConnection("jdbc:sqlite:test.db");
Statement stat = conn.createStatement();
stat.executeUpdate("drop table if exists people;");
stat.executeUpdate("create table people (name, occupation);");
PreparedStatement prep = conn.prepareStatement(
"insert into people values (?, ?);");
prep.setString(1, "Gandhi");
prep.setString(2, "politics");
prep.addBatch();
prep.setString(1, "Turing");
prep.setString(2, "computers");
prep.addBatch();
conn.setAutoCommit(false);
prep.executeBatch();
conn.setAutoCommit(true);
ResultSet rs = stat.executeQuery("select * from people;");
while (rs.next()) {
System.out.println("name = " + rs.getString("name"));
System.out.println("job = " + rs.getString("occupation"));
}
rs.close();
conn.close();
}
}
It loads a class dynamically. What does Class.forname method do? is a good article about it and it also explains why database drivers needs it:
Let's see why you need Class.forName() to load a driver into memory. All JDBC Drivers have a static block that registers itself with DriverManager and DriverManager has static an initializer only.
The MySQL JDBC Driver has a static initializer looks like this:
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
JVM executes the static block and the Driver registers itself with the DriverManager.
You need a database connection to manipulate the database. In order to create the connection to the database, the DriverManager class has to know which database driver you want to use. It does that by iterating over the array (internally a Vector) of drivers that have registered with it and calls the acceptsURL(url) method on each driver in the array, effectively asking the driver to tell it whether or not it can handle the JDBC URL.
The Class.forName statement is making sure that the class that implements the JDBC driver for sqlite3 is loaded and registered with the JDBC factory mechanism.
When you call DriverManager.getConnection(), it looks for classes that are registered and claim to be able to handle the connection string. If no such class is found, it can't create the connection.
Related
I'm learning about JDBC and I have learned the steps: open connection, execute statement, get result, etc. I know about Connection, Statements and the other interfaces, but I just found a tutorial with another class, the Connector class. And I don't understand what exactly we can do with this Connector class. I have made some app without this class and I don't understand why do I need the Connector class? Any feedback will be apreciated!
Here is the code:
public Set getAllUsers() {
Connector connector = new Connector();
Connection connection = connector.getConnection();
try {
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM user");
Set users = new HashSet();
while(rs.next())
{
User user = extractUserFromResultSet(rs);
users.add(user);
}
return users;
} catch (SQLException ex) {
ex.printStackTrace();
}
return null;
}
UPDATE:
This is the link where you can find the entire code: https://dzone.com/articles/building-simple-data-access-layer-using-jdbc
Your Connector is probably a class with a factory method:
the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created.
Basically it is a utility class to create a Connection hiding the complexity of connection creation.
I am using the c3p0 library as my datasource object.
I want to create a JDBC helper class that helps reduce the boilerplate code that JDBC has and I am wondering if my implementation is correct and are following best practices? Also, if there is an already existing library that provides these functionalities, like QueryRunner, maybe?
Most of my queries returns a list of results of a specified column. Will it be okay if I use the following helper method for all my queries?
public List<String> retrieveSQLQuery(String sqlQuery, String column) {
List<String> values = new ArrayList<>();
try (Connection conn = getConnection();
PreparedStatement statement = conn.prepareStatement(sqlQuery);
ResultSet rs = statement.executeQuery(sqlQuery)) {
while (rs.next()) {
values.add(rs.getString(column));
}
} catch (SQLException e) {
e.printStackTrace();
}
return values;
}
The getConnection() method lives in a JDBCUtil class which provides the connection to the datasource object. This helper class will be extending JDBCUtil thus why it has access to that method.
I also know that frameworks like spring and Hibernate provide utilities, however, those frameworks are too large for my project.
For university, it is my excercise to develop a multiplayer game with Java. The communication between the clients shall not be handled with sockets or the like, but with the help of a MySQL database where the clients are adding their steps in the game. Because it is a game of dice, not a lot of queries are needed. (approximiately 30 queries per gaming session are needed).
I never used MySQL in connection with Java before, so this maybe is a beginner's fault. But actually, I often get an exception during the execution of my java project.
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: User my_username already has more than 'max_user_connections' active connections
My queries are executed in a DatabaseHelper.java class. The results are returned and evaluated in another class of the project. Since I use an MVC pattern, I evaluate the results in a controller or model class.
This for example is one of my quers in the DatabaseHelper.java class. The other queries are similar:
private static Connection conn;
private Connection getConn() {
return conn;
}
public void db_connect() throws ClassNotFoundException, SQLException{
// JDBC Klassen laden
Class.forName(dbClassName);
// Verbindungsversuch auf 5 Sekunden setzen
DriverManager.setLoginTimeout(5);
this.setConn(DriverManager.getConnection(CONNECTION,p)); // p contains the username and the database
}
public void db_close(){
try {
this.getConn().close();
} catch (SQLException e) {
if(GLOBALVARS.DEBUG)
e.printStackTrace();
}
}
public String[] query_myHighscores(int gameid, PlayerModel p) throws SQLException{
List<String> rowValues = new ArrayList<String>();
PreparedStatement stmnt;
if(gameid == GLOBALVARS.DRAGRACE)
stmnt = this.getConn().prepareStatement("SELECT score FROM highscore WHERE gid = ? and pname = ? ORDER BY score ASC LIMIT 0,3");
else
stmnt = this.getConn().prepareStatement("SELECT score FROM highscore WHERE gid = ? and pname = ? ORDER BY score DESC LIMIT 0,3");
stmnt.setInt(1, gameid);
stmnt.setString(2, p.getUname());
ResultSet rs = stmnt.executeQuery();
rs.beforeFirst();
while(rs.next()){
rowValues.add(rs.getString(1));
}
stmnt.close();
rs.close();
return (String[])rowValues.toArray(new String[rowValues.size()]);
}
The CONNECTION string is a string which looks like jdbc:mysql://my_server/my_database
In the HighscoreGUI.java class, I request the data like this:
private void actualizeHighscores(){
DatabaseHelper db = new DatabaseHelper();
try{
db.db_connect();
String[] myScoreDragrace = db.query_myHighscores(GLOBALVARS.GAME1); // id of the game as parameter
// using the string
} finally {
db.db_close();
}
So I tried:
Closing the statement and the ResultSet after each query
Used db_close() to close the connection to the dabase in the finally-block
Never returning a ResultSet (found out this may become a performance leak)
The stacktrace leads in the DatabaseHelper.java class to the line
this.setConn(DriverManager.getConnection(CONNECTION,p));
But I cannot find my mistake why I still get this exception.
I cannot change every settings for the database since this is a shared host. So I'd prefer a solution on Java side.
The problem is that you exceed your allowed set of connections to that database. Most likely this limit is exactly or very close to "1". So as soon as you request your second connection your program crashes.
You can solve this by using a connection pooling system like commons-dbcp.
That is the recommended way of doing it and the other solution below is only if you may not use external resources.
If you are prohibited in the external code that you might use with your solution you can do this:
Create a "Database" class. This class and only this class ever connects to the DB and it does so only once per program run. You set it up, it connects to the database and then all the queries are created and run through this class, in Java we call this construct a "singleton". It usually has a private constructor and a public static method that returns the one and only instance of itself. You keep this connection up through the entire livetime of your program and only reactivate it if it gets stall. Basically you implement a "Connection Pool" for the specific case of the pool size "1".
public class Database {
private static final Database INSTANCE = new Database();
private Database() {}
public static Database getInstance() {
return INSTANCE;
}
// add your methods here.
}
When the program terminates, close the Connection (using a shutdown hook).
I'm trying to generate some sql files in my java application.
The application will not execute any sql statements, just generate a file with sql statements and save it.
I'd like to use the java.sql.PreparedStatement to create my statements so that i don't have to validate every string etc. with my own methods.
Is there a way to use the PreparedStatement without the calling java.sql.Connection.prepareStatement(String) function, because I don't have a java.sql.Connection?
Take a look at this Java library: http://openhms.sourceforge.net/sqlbuilder/
I'm guessing that until you've got a sql connection, the parser won't know what rules to apply. I'm guessing that it's actually the SQL driver or even server that's compiling the sql statement.
Assuming your sql is simple enough, then how about using a cheap connection, like, say a sqlite connection.
SQLite will create a new database on the fly if the database you're attempting to connect to does not exist.
public Connection connectToDatabase() {
// connect to the database (creates new if not found)
try {
Class.forName("org.sqlite.JDBC");
conn = DriverManager.getConnection("jdbc:sqlite:mydatabase.db");
// initialise the tables if necessary
this.createDatabase(conn);
}
catch (java.lang.ClassNotFoundException e) {
System.out.println(e.getMessage());
}
catch (java.sql.SQLException e) {
System.out.println(e.getMessage());
}
return conn;
}
Not really. Preparing a statement in most cases means that it will be compiled by DBMS which is "hard" without connection.
http://java.sun.com/docs/books/tutorial/jdbc/basics/prepared.html
This is a dastardly devious problem, thankfully it's pretty easy to cope with:
public class PreparedStatementBuilder
{
private String sql; // the sql to be executed
public PreparedStatementBuilder(final String sql) { this.sql = sql; }
protected void preparePrepared(final PreparedStatement preparedStatement)
throws SQLException
{
// this virtual method lets us declare how, when we do generate our
// PreparedStatement, we want it to be setup.
// note that at the time this method is overridden, the
// PreparedStatement has not yet been created.
}
public PreparedStatement build(final Connection conn)
throws SQLException
{
// fetch the PreparedStatement
final PreparedStatement returnable = conn.prepareStatement(sql);
// perform our setup directives
preparePrepared(returnable);
return returnable;
}
}
To use, just write an anonymous class that overrides void preparePrepared(PreparedStatement):
final String sql = "SELECT * FROM FOO WHERE USER = ?";
PreparedStatementBuilder psBuilder = new PreparedStatementBuilder(sql){
#Override
protected void preparePrepared(PreparedStatement preparedStatement)
throws SQLException
{
preparedStatement.setString(1, "randal");
}};
return obtainResultSet(psBuilder);
Presto! You now have a way to work with a PreparedStatement without yet having built it. Here's an example showing the minimal boilerplate you'd otherwise have to copy paste to kingdom come, every time you wanted to write a different statement:
public ResultSet obtainResultSet(final PreparedStatementBuilder builder)
throws SQLException {
final Connection conn = this.connectionSource.getConnection();
try
{
// your "virtual" preparePrepared is called here, doing the work
// you've laid out for your PreparedStatement now that it's time
// to actually build it.
return builder.build(conn).executeQuery();
}
finally
{
try { conn.close(); }
catch (SQLException e) { log.error("f7u12!", e); }
}
}
You really really don't want to be copy pasting that everywhere, do you?
Try implementing PreparedStatement.
Example : class YourOwnClass implements PreparedStatement {
// 1. Do implement all the methods ,
2. Get the minimal logic to implement from OraclePreparedStatement(classes12.jar) or
sun.jdbc.odbc.JdbcOdbcCallableStatement
}
Does anyone have examples of how to use DBMS_APPLICATION_INFO package with JBOSS?
We have a various applications which run within JBOSS and share db pools. I would like, at the start of each session these applications to identify themselves to the database using DBMS_APPLICATION_INFO so I can more easily track which sections of the application is causing database issues.
I'm not too familiar with session life cycles in JBOSS, but at the end of the day, what needs to happen is at the start and end of a transaction, this package needs to be called.
Has anyone done this before?
If you are using JBoss, you can use a "valid-connection-checker".
This class is normaly used to check the validity of the Connection.
But, as it will be invoked every time the Connection pool gives the user a Connection, you can use it to set the DBMS_ APPLICATION _INFO.
You declare such a class in the oracle-ds.xml like this:
<local-tx-datasource>
<jndi-name>jdbc/myDS</jndi-name>
<connection-url>jdbc:oracle:thin:#10.10.1.15:1521:SID</connection-url>
<driver-class>oracle.jdbc.driver.OracleDriver</driver-class>
<security-domain>MyEncryptDBPassword</security-domain>
<valid-connection-checker-class-name>test.MyValidConn</valid-connection-checker-class-name>
<metadata>
<type-mapping>Oracle9i</type-mapping>
</metadata>
</local-tx-datasource>
Your class must implement the org.jboss.resource.adapter.jdbc.ValidConnectionChecker interface.
If you use Maven, you can include this interface with the following dependency:
<dependency>
<groupId>jboss</groupId>
<artifactId>jboss-common-jdbc-wrapper</artifactId>
<version>3.2.3</version>
<scope>provided</scope>
</dependency>
This interface has only one method: isValidConnection.
I copy my implementation:
public SQLException isValidConnection(Connection arg0) {
CallableStatement statement;
try {
statement = arg0.prepareCall("call dbms_application_info.set_client_info('"+getInfos()+"')");
statement.execute();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
Hope it helps !
BenoƮt
yes, you can write a wrapper class around your connection pool, and a wraper around the connection
so lets say you have:
OracleConnection conn=connectionPool.getConnection("java:scott#mydb");
Change it to:
public class LoggingConnectionPool extends ConnectionPool{
public OracleConnection getConnection(String datasourceName, String module, String action){
OracleConnection conn=getConnection(datasourceName);
CallableStatement call=conn.preparedCall("begin dbms_application_info.setModule(module_name => ?, action_name => ?); end;");
try{
call.setString(1,module);
call.setString(2,action);
call.execute();
finally{
call.close();
}
return new WrappedOracleConnection(conn);
}
Note the use of WrappedOracleConnection above. You need this because you need to trap the close call
public class WrappedOracleConnection extends OracleConnection{
public void close(){
CallableStatement call=this.preparedCall("begin dbms_application_info.setModule(module_name => ?, action_name => ?); end;");
try{
call.setNull(1,Types.VARCHAR);
call.setNull(2,Types.VARCHAR);
call.execute();
finally{
call.close();
}
}
// and you need to implement every other method
//for example
public CallableStatement prepareCall(String command){
return super.prepareCall(command);
}
...
}
Hope this helps, I do something similar on a development server to catch connections that are not closed (not returned to the pool).
In your -ds.xml, you can set a connection property called v$session.program and the value of that property will populate the PROGRAM column of each session in the V$SESSION view created for connections originating from your connection pool. I usually set it to the jboss.server.name property.
See here for an example.