minucha
12/14/2019, 9:25 AMDataSource
class which configures Hikari
public class DataSource {
private static HikariConfig config = new HikariConfig();
private static HikariDataSource ds;
static {
config.setJdbcUrl("jdbc:<mysql://username>:<mailto:password@q2gen47hi68k1yrb.chr7pe7iynqr.eu-west-1.rds.amazonaws.com|password@q2gen47hi68k1yrb.chr7pe7iynqr.eu-west-1.rds.amazonaws.com>:3306/mmylxkukgpzvjvfx");
config.setUsername("username");
config.setPassword("password");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
config.addDataSourceProperty("cachePrepStmts", "true");
ds = new HikariDataSource(config);
}
private DataSource() {
}
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
}
In all tutorials I followed, they show this code or similer one but they don’t tell where and how to use the getConnection()
.
And the question is when, where and how do I call the getConnecion()
method?
Am I going to call it in every request I receive (in every api method defined in every single controller) ?
@GetMapping(path = "/all")
public @ResponseBody Iterable<ExampleEntity> getAllUsers() {
try {
Connection connection = DataSource.getConnection();
// what am I gonna do with the connection ?
return mExampleService.getAll();
} catch (SQLException ex) {
System.err.println("Exception Occurred");
}
}
Jukka Siivonen
12/14/2019, 12:40 PMminucha
12/14/2019, 12:50 PMfitzoh
12/14/2019, 4:05 PMJdbcTemplate
is part of the Spring framework, you can find the javadoc for it here: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jdbc/core/JdbcTemplate.html
and some text docs here:
https://docs.spring.io/sspring/docs/current/spring-framework-reference/data-access.html#jdbc
It provides a bunch of functions to make it easier to perform sql queriesfitzoh
12/14/2019, 4:05 PMDataSource
as an argumentfitzoh
12/14/2019, 4:06 PMfitzoh
12/14/2019, 4:06 PMHikariDataSource
, then it intelligently manages pooling for you, so that connections are reused instead of creating a new one each time, which is expensivefitzoh
12/14/2019, 4:07 PMfitzoh
12/14/2019, 4:08 PMfitzoh
12/14/2019, 4:08 PMJdbcTemplate
fitzoh
12/14/2019, 4:11 PMfitzoh
12/14/2019, 4:12 PMfitzoh
12/14/2019, 4:12 PMfitzoh
12/14/2019, 4:12 PMJdbcTemplate
with a hikari connection pool under the coversnicholasnet
12/15/2019, 4:51 PMJukka Siivonen
12/15/2019, 5:37 PMfitzoh
12/15/2019, 5:38 PMEven better use R2BC package now GAeh... If you're just getting started figuring out all the reactive stuff sounds like a lot of overhead
minucha
12/16/2019, 7:54 AMJdbcTemplate
. However, I couldn’t test the app, because when I uploaded the app to Heroku, it was still saying about the “10 max connection”.
I think, I will need to test it in localhost.minucha
12/16/2019, 7:55 AMJawsDB
. In the free plan, I am allowed to make max 10 connectionsminucha
12/16/2019, 7:56 AMminucha
12/16/2019, 8:00 AMJdbcTemplate
… I am gonna ask them later after I test couple of stuff 🙂Matteo Mirk
12/16/2019, 11:39 AMminucha
12/16/2019, 11:45 AMDataSource
class (it is in the original post)?
And what am I gonna do with the Connection
object ?Matteo Mirk
12/16/2019, 11:52 AMHikariConfig
class has this property you can set setMaximumPoolSize(int maxPoolSize)
, that should do the trick. Interesting fact is that if you look at the source (https://github.com/openbouquet/HikariCP/blob/master/src/main/java/com/zaxxer/hikari/HikariConfig.java#L110) it has a default value of 10… weird, it should work out of the box for your case! 🤔 Anyway it’s better to set it explicitly.
When you gey a Connection
object, from then on it’s all basic JDBC handling: https://docs.oracle.com/javase/tutorial/jdbc/basics/processingsqlstatements.htmlMatteo Mirk
12/16/2019, 11:56 AMExampleService
minucha
12/16/2019, 11:56 AMMatteo Mirk
12/16/2019, 11:57 AMminucha
12/16/2019, 11:58 AMnkiesel
12/16/2019, 8:39 PMtry (Connection connection = DataSource.getConnection()) {
return mExampleService.getAll(connection);
}
minucha
12/16/2019, 8:42 PMpublic void addBook(ExampleBook book) {
String name = book.getName();
String author = book.getAuthor();
String description = book.getDescription();
String sqlQuery = "insert into books (`name`,`author`,`description`)" +
" values('" + name + "', '" + author + "', '" + description + "');";
Statement statement = null;
try {
Connection connection = DataSource.getConnection();
statement = connection.createStatement();
int rs = statement.executeUpdate(sqlQuery);
L.e("hop", "int : " + rs);
} catch (SQLException ex) {
L.e("Exception occurred");
ex.printStackTrace();
} finally {
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
There are two problems I think:
1. Two try catches
2. SQL statement
(3) too long and jibberish methodJukka Siivonen
12/16/2019, 8:44 PMminucha
12/16/2019, 8:45 PM@Autowired
private ExampleBookRepo mBookRepo;
public void addBook2(ExampleBook book) {
mBookRepo.save(book);
}
here ExampleBookRepo
is an interface that is extended from CrudRepository
and it was awesome working with it. So clean and readable.Jukka Siivonen
12/16/2019, 8:48 PMminucha
12/16/2019, 8:50 PMSQL injectionlooked it up, wow, never thought about it.
For that you need to look into Spring Data JPACan’t we use both HikariCP with its
getConnection()
and Spring Data JPA ?nkiesel
12/17/2019, 1:01 AMclose
on. SQL injection is prevented by using prepared statements. JDBC is pretty low-level (look at Spring template or jdbi for nicer APIs). But a "pure JDBC" would look like this (note that with try expressions you no longer need the finally
block):
public void addBook(ExampleBook book) {
String sqlQuery = "insert into books (`name`,`author`,`description`)" +
" values(?, ?, ?);";
try (
Connection connection = DataSource.getConnection();
PreparedStatement statement = connection.prepareStatement(sqlQuery)) {
statement.setString(1, book.getName());
statement.setString(2, book.getAuthor());
statement.setString(3, book.getDescription());
int rs = statement.executeUpdate();
L.e("hop", "int : " + rs);
} catch (SQLException ex) {
L.e("Exception occurred");
ex.printStackTrace();
}
}
minucha
12/17/2019, 7:49 AMstatement.setString(1, book.getName());
woosh, mindblowing. Thank you, I learned a great deal of staff today.Matteo Mirk
12/17/2019, 9:26 AMminucha
12/17/2019, 10:07 AMMatteo Mirk
12/17/2019, 4:24 PMnkiesel
12/17/2019, 6:53 PMfun addBook(ds: DataSource, book: ExampleBook): Int {
val sqlQuery = "insert into books (name, author, description) values(?, ?, ?)"
ds.connection.use { con ->
con.prepareStatement(sqlQuery).use { statement ->
statement.setString(1, book.name)
statement.setString(2, book.author)
statement.setString(3, book.description)
return statement.executeUpdate()
}
}
}