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:



hibernate change database swing example empty data

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:

hibernate change database swing example load data

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:


About the Author:

is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.



Add comment

   


Comments 

#1Albin2020-12-03 13:15
Could you please post a spring-hibernate dynamic connection to the DB example? The DB name is passed as a parameter or from a table with a different DB connection anyway.
Quote