Hibernate Change Database Dynamically at Runtime Example
- Details
- Written by Nam Ha Minh
- Last Updated on 10 August 2019   |   Print Email
In this Hibernate tutorial, I will share with you how to write code that changes database (or schema) dynamically at runtime for a Java application that uses Hibernate framework. Sometimes you have to develop an application that work with multiple databases and it allows the users to switch among different databases smoothly, without restarting the application.
You know, we usually use Hibernate with a fixed database whose connection information is specified via hibernate.cfg.xml file. To allow changing database dynamically at runtime, we need to use programmatic configuration for Hibernate. For example, the following code snippet illustrates how to create a SessionFactory from a Configuration object:
Configuration config = new Configuration(); config.setProperty("hibernate.connection.driver_class", "com.mysql.jdbc.Driver"); config.setProperty("hibernate.connection.url", "jdbc:mysql://localhost:3306/bookstoredb"); config.setProperty("hibernate.connection.username", "root"); config.setProperty("hibernate.connection.password", "password"); config.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect"); config.addAnnotatedClass(ModelClass1.class); config.addAnnotatedClass(ModelClass2.class); try { SessionFactory sessionFactory = config.buildSessionFactory(); Session session = sessionFactory.openSession(); // work with the session session.close(); sessionFactory.close(); } catch (Exception ex) { ex.printStackTrace(); }
As you can see, the database connection information is set in programmatic way – not fixed in XML file – so we can base on that to change database at runtime. So based on that Hibernate programmatic configuration, code a utility method that opens a SessionFactory based on the database name provided, as follows:
public static SessionFactory getSessionFactory(String databaseName) { Configuration config = new Configuration(); config.setProperty("hibernate.connection.driver_class", "com.mysql.jdbc.Driver"); config.setProperty("hibernate.connection.url", "jdbc:mysql://localhost:3306/" + databaseName); config.setProperty("hibernate.connection.username", "root"); config.setProperty("hibernate.connection.password", "password"); config.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect"); config.addAnnotatedClass(Users.class); SessionFactory sessionFactory = config.buildSessionFactory(); return sessionFactory; }
Pay attention to the line that allows the database name can be changed at runtime:
config.setProperty("hibernate.connection.url", "jdbc:mysql://localhost:3306/" + databaseName);
Then you can use this method as follows:
// get selected database name from the user: String databaseName = … SessionFactory sessionFactory = HibernateUtil.getSessionFactory(databaseName); Session session = sessionFactory.openSession(); // work with session... session.close(); sessionFactory.close();
The names of databases on the server may not be fixed or not known at runtime, so code the second utility method that lists all names of databases on the server as follows:
public static List<String> getDatabaseNames(String filter) throws SQLException { List<String> dbNames = new ArrayList<>(); String databaseURL = "jdbc:mysql://localhost:3306/"; String username = "root"; String password = "password"; Connection connection = DriverManager.getConnection(databaseURL, username, password); DatabaseMetaData metadata = connection.getMetaData(); ResultSet result = metadata.getCatalogs(); while (result.next()) { String aDBName = result.getString(1); if (aDBName.contains(filter)) { dbNames.add(aDBName); } } connection.close(); return dbNames; }
Here, we use pure JDBC code to get the names of databases on the server, filtered by the String parameter filter so we can get only relevant database names.
Put the above methods in a utility class called HibernateUtil.
And now I will show you an example Java Swing program that allows the user to read data from different databases. The program looks like this:
As you can see, upon startup the program presents some database names in a dropdown list. The user can choose one database and click the Get Data button to read the data from that database into the table underneath. For example, getting data from the bookstoredb database:
Suppose that all databases have same table structure.
For your reference, below I list code of the relevant Java classes.
Code of the main Java Swing program:
package net.codejava.db; import java.awt.*; import java.awt.event.*; import java.sql.*; import java.util.*; import javax.swing.*; import org.hibernate.*; import org.hibernate.query.*; /** * Copyright (C) www.codejava.net * @author Nam Ha Minh * */ public class HibernateChangeDatabaseSwing extends JFrame implements ActionListener { private JLabel labelSelect = new JLabel("Choose Database: "); private JComboBox<String> comboDatabaseNames = new JComboBox<>(); private JButton buttonGetData = new JButton("Get Data"); private JTable tableData = new JTable(); private CustomTableModel tableModel = new CustomTableModel(); public HibernateChangeDatabaseSwing() throws HeadlessException { super("Users Manager"); setLayout(new GridBagLayout()); GridBagConstraints constraint = new GridBagConstraints(); constraint.gridx = 0; constraint.gridy = 0; constraint.insets = new Insets(10, 10, 10, 10); add(labelSelect, constraint); constraint.gridx = 1; try { List<String> databaseNames = HibernateUtil.getDatabaseNames("book"); for (String dbName : databaseNames) { comboDatabaseNames.addItem(dbName); } } catch (SQLException ex) { JOptionPane.showMessageDialog(this, ex.getMessage()); } add(comboDatabaseNames, constraint); constraint.gridx = 2; add(buttonGetData, constraint); buttonGetData.addActionListener(this); constraint.gridx = 0; constraint.gridy = 1; constraint.gridwidth = 3; constraint.weightx = 1.0; constraint.weighty = 1.0; constraint.fill = GridBagConstraints.BOTH; tableData.setModel(tableModel); add(new JScrollPane(tableData), constraint); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(640, 480); setLocationRelativeTo(null); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new HibernateChangeDatabaseSwing().setVisible(true); } }); } @Override public void actionPerformed(ActionEvent evt) { String databaseName = (String) comboDatabaseNames.getSelectedItem(); loadDataIntoTable(databaseName); } private void loadDataIntoTable(String databaseName) { SessionFactory sessionFactory = HibernateUtil.getSessionFactory(databaseName); Session session = sessionFactory.openSession(); String hql = "from Users"; Query<Users> query = session.createQuery(hql); List<Users> listUsers = query.list(); tableModel.setData(listUsers); tableModel.fireTableDataChanged(); session.close(); sessionFactory.close(); } }
Code of the table model class:
package net.codejava.db; import java.util.ArrayList; import java.util.List; import javax.swing.table.AbstractTableModel; /** * Copyright (C) www.codejava.net * @author Nam Ha Minh * */ public class CustomTableModel extends AbstractTableModel { private String[] columnNames = {"User ID", "E-mail", "Full name", "Password"}; private List<Users> listData = new ArrayList<>(); public void setData(List<Users> listData) { this.listData = listData; } @Override public int getRowCount() { return listData.size(); } @Override public int getColumnCount() { return columnNames.length; } @Override public String getColumnName(int column) { return columnNames[column]; } @Override public Object getValueAt(int rowIndex, int columnIndex) { Object cellValue = null; Users user = listData.get(rowIndex); if (columnIndex == 0) cellValue = user.getUserId(); if (columnIndex == 1) cellValue = user.getEmail(); if (columnIndex == 2) cellValue = user.getFullName(); if (columnIndex == 3) cellValue = user.getPassword(); return cellValue; } }
Code of the Java model class:
package net.codejava.db; import javax.persistence.*; @Entity public class Users { private Integer userId; private String email; private String fullName; private String password; public Users() { } public Users(Integer userId, String email, String fullName, String password) { this(email, fullName, password); this.userId = userId; } public Users(String email, String fullName, String password) { super(); this.email = email; this.fullName = fullName; this.password = password; } @Column(name = "user_id") @Id @GeneratedValue(strategy = GenerationType.IDENTITY) public Integer getUserId() { return userId; } @Column(name = "full_name") public String getFullName() { return fullName; } // other getters and setters... }
That’s how to write code to change database dynamically at runtime with Hibernate framework. Based on this tutorial, you can also implement the same functionality for Java web applications.
Related Tutorials:
Other Hibernate Tutorials:
- Hibernate Hello World Tutorial for Beginners with Eclipse and MySQL
- Java Hibernate JPA Annotations Tutorial for Beginners
- Hibernate One-to-One Association on Primary Key Annotations Example
- Hibernate One-to-Many Association Annotations Example
- Hibernate Many-to-Many Association Annotations Example
- Hibernate Enum Type Mapping Example
- Hibernate Binary Data and BLOB Mapping Example
- Hibernate Query Language (HQL) Example
- Java Hibernate Reverse Engineering Tutorial with Eclipse and MySQL
Comments