H2 in-memory creating a server to access via Shell - java

I'm using the DataSourceFactory of dropwizard and H2 to create an in-memory db for testing. Here is what I have
private static final String DBNAME = String.format("JDBITest-%d", System.currentTimeMillis());
protected final DataSourceFactory config = new DataSourceFactory();
{
final String url = String.format("jdbc:h2:mem:%s;", DBNAME) +
"MODE=MySQL;" +
"TRACE_LEVEL_FILE=3;" +
"DB_CLOSE_DELAY=-1;" +
"IGNORECASE=TRUE";
System.out.println("Creating in memory H2 using " + url);
BootstrapLogging.bootstrap();
config.setUrl(url);
config.setUser("sa");
config.setDriverClass("org.h2.Driver");
config.setValidationQuery("SELECT 1");
}
#Before
public void setUp() throws Exception {
Server server = Server.createTcpServer().start(); // (4)
System.out.println("Server started and connection is open.");
System.out.println("URL: jdbc:h2:" + server.getURL() + "/mem:" + DBNAME);
}
When this runs I see
Creating in memory H2 using jdbc:h2:mem:JDBITest-1541641621470;MODE=MySQL;TRACE_LEVEL_FILE=3;DB_CLOSE_DELAY=-1;IGNORECASE=TRUE
Server started and connection is open.
URL: jdbc:h2:tcp://0.0.17.56:9092/mem:JDBITest-1541641621470
Why is the TCP 0.0.17.56? I cannot access this nor can I use the H2.jar to access the shell.

There are several wrong things here.
H2 has different connections modes. In your example you configure DataSourceFactory for in memory connection, but then in #Before method you create new instance of H2 with tcp based connection. More about connection modes here.
So now you have basically 2 instances of H2, in memory and tcp and they are completely unrelated. So you probably need to have only 1 connection type configured for you tests.
If you want to connect to your H2 db outside of JVM (from browser for example) - then you need to have tcp-based connection.
To be able to connect to db from browser you also need to run console application. Which should be inside h2.jar with command like that java -jar h2*.jar. More about this here.
And finally, this peace of code should suitable for you (with in-memory connection):
private static final String DBNAME = String.format("JDBITest-%d", System.currentTimeMillis());
private ManagedDataSource dataSource;
#Before
public void setUp() {
System.out.println("Server started and connection is open.");
final String url = String.format("jdbc:h2:mem:%s;", DBNAME) +
"MODE=MySQL;" +
"TRACE_LEVEL_FILE=3;" +
"DB_CLOSE_DELAY=-1;" +
"IGNORECASE=TRUE";
System.out.println("Creating in memory H2 using " + url);
DataSourceFactory config = new DataSourceFactory();
BootstrapLogging.bootstrap();
config.setUrl(url);
config.setUser("sa");
config.setDriverClass("org.h2.Driver");
config.setValidationQuery("SELECT 1");
dataSource = config.build(null, "test");
}
#Test
public void test() throws SQLException {
Connection connection = dataSource.getConnection();
connection.createStatement().executeUpdate("CREATE TABLE TEST (`id` INT)");
connection.createStatement().executeUpdate("INSERT INTO TEST (`id`) VALUES (1)");
ResultSet resultSet1 = connection.createStatement().executeQuery("SELECT * FROM TEST WHERE `id` = 1");
resultSet1.next();
resultSet1.getInt(1);
System.out.println("Found ID: " + resultSet1.getInt(1));
}
Out:
Server started and connection is open.
Creating in memory H2 using jdbc:h2:mem:JDBITest-1541649996267;MODE=MySQL;TRACE_LEVEL_FILE=3;DB_CLOSE_DELAY=-1;IGNORECASE=TRUE
Found ID: 1

Related

Run java method to start database before Tomcat deploy

I am developing a web project with HSQLDB persistence. My database instance is on server mode, therefore, I need to run a cmd script/ Java method to access my schema.
Tomcat is the container I use to drop my war on port 8080. Gradle is my build system.
Currently I am using the following main method before I deploy my app to properly access my database on runtime:
public static void main(String[] args) throws IOException, ServerAcl.AclFormatException {
final String URL = "file:~/db/cursago";
String user = "user";
String password = "password";
HsqlProperties p = new HsqlProperties();
p.setProperty("server.database.0",URL+";user="+user+";password="+password);
p.setProperty("server.dbname.0","cursago");
Server server = new Server();
server.setProperties(p);
server.setLogWriter(null);
server.setErrWriter(null);
server.start();
System.out.println("Database is running with path: " + URL);
System.out.println("Username: " + user+", Password: " + password);
}
I would like to know if there's a way of making Tomcat/Gradle/IntelliJ IDEA run this main method before a project deploy, instead of running this script by hand.
from here:
you could run the content of your main in the onApplicationEvent like:
public class ApplicationListenerBean implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
final String URL = "file:~/db/cursago";
String user = "user";
String password = "password";
HsqlProperties p = new HsqlProperties();
p.setProperty("server.database.0",URL+";user="+user+";password="+password);
p.setProperty("server.dbname.0","cursago");
Server server = new Server();
server.setProperties(p);
server.setLogWriter(null);
server.setErrWriter(null);
server.start();
System.out.println("Database is running with path: " + URL);
System.out.println("Username: " + user+", Password: " + password);
}
}
This will trigger on every event, that could be application started or redeployed and happens before your application handles requests.
You also can wire in your properties.
There are some difficulties if the server is already running and it can't run in this scope only.

Migrate sql schema to many databases using Flyway

I'm trying to write a simple Java sample application which uses Flyway to migrate many databases on one IP. When I run this application it completes without error but nothing seems to happen, the schema_version table is not created.
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("databaseConfig.xml");
ClientDAO clientDao = ctx.getBean("clientDao", ClientDAO.class);
List<String> clients = clientDao.getClients();
Flyway flyway = new Flyway();
for (String client : clients) {
flyway.setDataSource("jdbc:mysql://" + STAGE_DB_IP +"/" + client, DB_USER, DB_PASSWORD);
flyway.baseline();
flyway.setBaselineOnMigrate(true);
flyway.migrate();
}
System.out.println("Done");
}
The databases already exist with tables.

Apache Camel 2.12: Adding bean to already existing context

I need to process a file on the app startup and create some objects out of the given information and then add them as beans to the camel context. Eg: Mysql DataSource object.
public static void load(CamelContext context) throws Exception {
JndiRegistry registry = (JndiRegistry) context.getRegistry();
PropertiesComponent pc = context.getComponent("properties", PropertiesComponent.class);
pc.setLocation("classpath:mysql.properties");
for (String mysql: pc.parseUri("{{mysqlConfigs}}").split(",")) {
String MYSQL_DB_URL = pc.parseUri("{{" + mysql + ".url}}");
String MYSQL_DB_USERNAME = pc.parseUri("{{" + mysql + ".username}}");
String MYSQL_DB_PASSWORD = pc.parseUri("{{" + mysql + ".passwd}}");
String DB_NAME = pc.parseUri("{{" + mysql + ".name}}");
MysqlDataSource mysqlDS = new MysqlDataSource();
mysqlDS.setURL(MYSQL_DB_URL);
mysqlDS.setUser(MYSQL_DB_USERNAME);
mysqlDS.setPassword(MYSQL_DB_PASSWORD);
registry.bind(DB_NAME, (DataSource) mysqlDS);
}
}
The code throws exception,
org.apache.camel.impl.PropertyPlaceholderDelegateRegistry cannot be cast to org.apache.camel.impl.JndiRegistry
Same error if I try to cast it to SimpleRegistry. Is there way this can be achieved this way or if any other methodology shall be adopted given that no more contexts are to be added.
Try:
JndiRegistry registry = context.getRegistry(JndiRegistry.class);

How to connect to different DB process from JDBC DataSource

I'm writing Java application with Apache Camel and use JDBC DataSource(Apache commons DBCP).
I can create many connections but all connections are handled in one Oracle client process, what I may see in sessions table select * from v$session.
The question is how to connect from one Java application to different Oracle processes to improve performance? If you know a way to do it using other Java technologies, not used in my example, it is also very interesting.
public static void main(String... args) throws Exception {
Main main = new Main();
String url = "some url";
String user = "user";
String password = "password";
DataSource dataSource = setupDataSource(url, user, password);
// bind dataSource into the registery
main.bind("oraDataSource", dataSource);
main.enableHangupSupport();
main.addRouteBuilder(new MyRouteBuilder());
main.run(args);
}
private static DataSource setupDataSource(String connectURI, String user, String password) {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("oracle.jdbc.driver.OracleDriver");
ds.setMaxActive(20);
LOG.info("max active conn: " + ds.getMaxActive());
ds.setUsername(user);
ds.setPassword(password);
ds.setUrl(connectURI);
return ds;
}
public class MyRouteBuilder extends RouteBuilder {
Processor logProcessor = new LogProcessor();
Processor createAnswer = new CreateAnswerProc();
Processor dbPaymentProcessor = new DbPaymentQueryProcessor();
/**
* Let's configure the Camel routing rules using Java code...
*/
public void configure() {
from("rabbitmq://localhost:5672/ps.vin_test_send?exchangeType=topic&autoDelete=false&queue=ps.test_send_queue&concurrentConsumers=20&threadPoolSize=20")
.unmarshal().json(JsonLibrary.Jackson, Payment[].class)
.process(dbPaymentProcessor)
.to("jdbc:oraDataSource")
.process(logProcessor)
.process(createAnswer)
.to("rabbitmq://localhost:5672/ps.vin_test?username=test&password=test&exchangeType=topic&autoDelete=false&routingKey=ps.vin_test_key&queue=vin_test_queue&concurrentConsumers=20");
}
So, the way for oracle is to change db propeties from dedicated to shared. And it will share processes between users. but it is not recomended and not give any performance.
Creation of multiple datasources only reduces performance.

H2 createTcpServer() does not create server?

after reading the H2 documentation, I wrote this simple application to create a H2 database in a local directory:
public static void main(String[] args) throws SQLException {
String path = "C:/Temp/H2/";
File fpath = new File(path);
fpath.mkdirs();
FileUtils.recursiveDelete(fpath);
String dbName = "tata";
String connection = "jdbc:h2:file:" + path + dbName;
Server server = Server.createTcpServer(connection);
server.start();
server.stop();
}
This program runs fine, but when I check in the target directory, the database is not there... (i am using release 1.3.161)
You need to actually access the database, files are created lazily:
server.start();
DriverManager.getConnection(connection);
server.stop();
Added line in the middle creates tata.h2.db file where expected (tested with 1.3.155).

Categories