Hibernate ===================== - A framework for persisting / saving java objects in a database - www.hibernate.org Benefits -------------- - Hibernate handles all the low level SQL - Minimizes amount of JDBC code that you have to develop - Hibernate provides ORM(Object to Relational Mapping) - It handles mapping between java class and database Java Class Database Table --------------- ------------------ Student.java student id : int > > id INT Primary Key firstName : String Hibernate first_name : Varchar(45) lastName : String last_name : Varchar(45) email : String < < email : Varchar(45) Saving and Retrieving java object with Hibernate --------------------------------------------------------------- // Create a java object Student theStudent = new Student("John", "Doe", "john@gmail.com"); // save it in database int theId = (Integer) session.save(theStudent); session : special Hibernate object It returns the id that its been assigned to that entry, and it is actually the primary key // retrieve from database using the primary key Student theStudent = session.get(Student.class, theId); // retrieve all the datas from a table Query query = session.createQuery("from Student"); List students = query.list(); Hibernate CRUD Apps C - Create Objects R - Read Objects U - Update Objects D - Delete Objects Hibernate and JDBC ------------------------- - Hibernate uses JDBC for all database communication Java Hibernate : JDBC Database App - It uses the Hibernate API, but in background it all goes through Standard JDBC API *** Hibernate 5.2 Requires Java 8 *********************************************************** Create a new user in MySQl Database ------------------------------------------- username : hbstudent password : hbstudent Through command line ------------------------------- CREATE USER 'hbstudent'@'localhost' IDENTIFIED BY 'hbstudent'; GRANT ALL PRIVILEGES ON * . * TO 'hbstudent'@'localhost'; # # Starting with MySQL 8.0.4, the MySQL team changed the # default authentication plugin for MySQL server # from mysql_native_password to caching_sha2_password. # # The command below will make the appropriate updates for your user account. # # See the MySQL Reference Manual for details: # https://dev.mysql.com/doc/refman/8.0/en/caching-sha2-pluggable-authentication.html # ALTER USER 'hbstudent'@'localhost' IDENTIFIED WITH mysql_native_password BY 'hbstudent'; Through Workbench --------------------- Open workbench --> open Local Instance MYSQL --> Management --> Users and Privilages --> Add Account --> Give name, password --> Administrative Roles --> Tick on DBA --> Apply --> Refresh --> After its added go to Home --> click on + symbol --> Give a connection name and username what you had given in there --> Test Connection --> Enter password that you had given --> OK --> New User Created I created Connection Name : Hibernate username : hibernate password : hibernate ******************************************************************************** Do this ------------------ 1. Create a new User in MySQL and create student table in it CREATE DATABASE IF NOT EXISTS `hb_student_tracker`; USE `hb_student_tracker`; -- -- Table structure for table `student` -- DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `id` int(11) NOT NULL AUTO_INCREMENT, `first_name` varchar(45) DEFAULT NULL, `last_name` varchar(45) DEFAULT NULL, `email` varchar(45) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; 2. Create a Project 1_Hibernate_Demo and create a new lib folder in it. 3. Go to www.hibernate.org and download Hibernate ORM JARs Maven depedency : org.hibernate hibernate-agroal 5.4.14.Final pom 4. Add the JAR files to lib folder i) The mysql-connector JAR ii) All the JAR files in D:\Spring & Hibernate\Hibernate\JARs\hibernate-ORM-release-5.4.14.Final\hibernate-release-5.4.14.Final\lib\required this folder 5. Build the path in Eclipse Test JDBC Connection =============================== package demo.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class Provider { public static Connection getMySQLConnection() throws ClassNotFoundException, SQLException { Connection con = null; Class.forName("com.mysql.cj.jdbc.Driver"); String url = "jdbc:mysql://localhost:3306/hb_student_tracker?useSSL=false"; // hb_student_tracker : database name String user = "hibernate"; // user-name String password = "hibernate"; //password try{ con = DriverManager.getConnection(url,user,password); if(con != null) System.out.println("Connection Established"); else System.out.println("Connection Error"); }catch (Exception e) { e.printStackTrace(); } return con; } // Class.forName("oracle.jdbc.OracleDriver"); // Connection oracle_con = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:db_name", "system", "password"); // In older version (5.0.11) the Driver class is in com.mysql.jdbc.Driver // In new mysql connector 8.0.16 the driver class is in com.mysql.cj.jdbc.Driver // download latest from https://mvnrepository.com/artifact/mysql/mysql-connector-java/8.0.16 public static void main(String[] args) throws ClassNotFoundException, SQLException { Connection mySQLConnection = Provider.getMySQLConnection(); System.out.println(mySQLConnection); mySQLConnection.close(); } } Hibernate Application Development Process ================================================ 1. Add hibernate configuration file 2. Annotate Java Class 3. Develop java code to perform database operation 1. Add hibernate configuration file ----------------------------------------- - It tells hibernate how to connect to database - Hibernate uses JDBC in the background for communicating with the database Create a hibernate.cfg.xml file in src directory of 1_Hibernate_Demo project hibernate.cfg.xml ------------------------- com.mysql.cj.jdbc.Driver jdbc:mysql://localhost:3306/hb_student_tracker?useSSL=false&serverTimezone=UTC hibernate hibernate 1 org.hibernate.dialect.MySQLDialect true true thread - If the value is "create" then the hibernate first drops the existing tables data and structure, then creates new tables and executes the operations on the newly created tables. The only problem with the value “create” is, we lose existing table data. - If the value is "validate" then hibernate only validates the table structure- whether the table and columns have existed or not. If the table doesn’t exist then hibernate throws an exception. Validate is the default value for hbm2ddl.auto. - If the value is "update" then, Hibernate checks for the table and columns. If a table doesn’t exist then it creates new tables and where as if a column doesn’t exist it creates new columns for it. But in the case of value “update” hibernate doesn’t drop any existing table, so that we don’t lose existing table data. - If the value is "create-drop" then, Hibernate first checks for a table and do the necessary operations and finally drops the table after all the operations were completed. The value “create-drop” is given for unit testing the hibernate code. hbm2ddl.auto Create Example: ======================================= Create Pojo class : Student.java --------------------------------------- public class Student { private int studentId; private String studentName; private String address; public int getStudentId() { return studentId; } public void setStudentId(int studentId) { this.studentId = studentId; } public String getStudentName() { return studentName; } public void setStudentName(String studentName) { this.studentName = studentName; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } } Create Hibernate Mapping File : student.hbm.xml -------------------------------------------------------- Hibernate configuration file: hibernate.cfg.xml ------------------------------------------------------- com.mysql.jdbc.Driver jdbc:mysql://localhost:3306/onlinetutorialspoint root 123456 create Run the Application : -------------------------------- import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import com.otp.hibernate.pojo.Student; public class Main { public static void main(String[] args) { Configuration configuration = new Configuration().configure("hibernate.cfg.xml"); StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder() .applySettings(configuration.getProperties()); SessionFactory factory = configuration.buildSessionFactory(builder.build()); Session session = factory.openSession(); Transaction transaction = session.beginTransaction(); Student student = new Student(); student.setStudentName("Chandra Shekhar"); student.setAddress("Hyderabad"); session.save(student); transaction.commit(); session.flush(); session.close(); System.out.println("Transaction Completed !"); } } 2. Annotate Java Class --------------------------- - Hibernate has an concept of Entity class, the class which is mapped to a database table. - The Pojo class will be annotated as @Entity - It will map the java class to the database table Java Class Database Table --------------- ------------------ Student.java student id : int > > id INT Primary Key firstName : String Hibernate first_name : Varchar(45) lastName : String last_name : Varchar(45) email : String < < email : Varchar(45) Two types of mapping --------------------------- 1. XML config file (legacy) 2. Java Annotation (modern, preferred) Java Annotations 1. Map class to table 2. Map field to column @Entity @Table(name="student") public class Student { @Id @Column(name="id") private int id; @Column(name="first_name") private String firstName; ... } ******************************************************************************************* Java 9 and higher has removed java.xml.bind from its default classpath. That is why we get the class not found exception. We have to explicitly add JAR files to the build path. Error: Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException For Java 9 and higher, you need to additional JAR files. 1. You need to download the following JAR files: javax.activation-1.2.0.jar jaxb-api-2.3.0.jar jaxb-core-2.3.0.jar jaxb-impl-2.3.0.jar 2. Copy the JAR files to the lib folder of your project and build path ************************************ Error: import of the javax.persistance.GenerationType saying its not accessible You may still encounter problems for "import of the javax.persistance.GenerationType saying its not accessible" To resolve this, apply the following steps 1. Right Click on the Project -> Properties --> Java Build Path --> Libraries --> JRE System Library --> IS Modular --> Edit --> in Available Modules select all --> click on => --> OK (In Module Properties -> Select All in Available modules and move to Explicitly included modules.) 4. Project->Clean... and Rebuild the Project and try again. ************************************* if you are using Maven then you can add this to your POM file javax.xml.bind jaxb-api 2.2.8 com.sun.xml.bind jaxb-core 2.2.8 com.sun.xml.bind jaxb-impl 2.2.8 com.sun.activation javax.activation 1.2.0 ************************************************************************************************* https://docs.jboss.org/hibernate/orm/5.0/manual/en-US/html/ ************************************************************************************************* Do this ------------------- 1. In 1_Hibernate_Demo create a package demo.entity 2. Create a POJO Student.java class package demo.entity; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name="student") public class Student { @Id @Column(name="id") private int id; @Column(name="first_name") private String firstName; @Column(name="last_name") private String lastName; @Column(name="email") private String email; public Student() { } public Student(String firstName, String lastName, String email) { super(); this.firstName = firstName; this.lastName = lastName; this.email = email; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Override public String toString() { return "Student [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", email=" + email + "]"; } } Why we are using JPA Annotation instead of Hibernate? JPA is a standard specification. Hibernate is an implementation of the JPA specification. Hibernate implements all of the JPA annotations. The Hibernate team recommends the use of JPA annotations as a best practice. 3. Develop java code to perform database operation ================================================================= SessionFactory :- Reads the hibernate config files - Creates session objects - Heavy weight object - Only create once in your app Session : Wraps a JDBC Connection Main object used to save/retrieve objects short-lived objects Retrieved from session factory Configuration cfg = new Configuration(); cfg.configure("hibernate.cfg.xml"); //we can simply say cfg.configure() and it will look for the file in your classpath by default cfg.addAnnotatedClass(Student.class); SessionFactory factory = cfg.buildSessionFactory(); //OR in one line SessionFactory factory = new Configuration() .configure("hibernate.cfg.xml") .addAnnotatedClass(Student.class) .buildSessionFactory(); Session session = factory.openSession(); // for this you have to manually close the session // OR, either use one of them Session session = factory.getCurrentSession(); //use this // using this will automatically close the session try{ // now use the session object to save/retrieve java objects }finally{ factory.close(); } getcurrentsession() and opensession() in hibernate ------------------------------------------------------------- openSession() : When you call SessionFactory. openSession , it always creates a new Session object and give it to you. You need to explicitly flush and close these session objects. : When you call SessionFactory.openSession, it always create new Session object afresh and give it to you. You need to explicitly flush and close these session objects. As session objects are not thread safe, you need to create one session object per request in multithreaded environment and one session per request in web applications too. getCurrentSession() : it will provide you session object which is in hibernate context and managed by hibernate internally. : When you call SessionFactory. getCurrentSession, it will provide you session object which is in hibernate context and managed by hibernate internally. It is bound to transaction scope. When you call SessionFactory. getCurrentSession , it creates a new Session if not exists , else use same session which is in current hibernate context. It automatically flush and close session when transaction ends, so you do not need to do externally. If you are using hibernate in single threaded environment , you can use getCurrentSession, as it is faster in performance as compare to creating new session each time. You need to add following property to hibernate.cfg.xml to use getCurrentSession method. thread Save a java object =============================== SessionFactory factory = new Configuration() .configure("hibernate.cfg.xml") .addAnnotatedClass(Student.class) .buildSessionFactory(); Session session = factory.getCurrentSession(); try{ //Create a student object Student theStudent = new Studnet("Debi", "Mishra", "debi@gmail.com"); //start transaction Transaction tx = session.beginTransaction(); // save the student session.save(theStudent); //commit transaction tx.commit(); // OR session.getTransaction().commit(); }finally{ factory.close(); } Do this --------------------- 1. In 1_Hibernate_Demo create a package demo.application 2. Create StudentDemo.java class package demo.application; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Student; public class StudentDemo { public static void main(String[] args) { // create a session factory // Configuration cfg = new Configuration(); // cfg.configure("hibernate.cfg.xml"); //we can simply say cfg.configure() and it will look for the file in your classpath by default // cfg.addAnnotatedClass(Student.class); // SessionFactory factory = cfg.buildSessionFactory(); SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Student.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { // Create a Student object System.out.println("Creating a new student object"); Student theStudent = new Student("Debi Prasad", "Mishra", "debiprasad@gmail.com"); // start the transaction Transaction tx = session.beginTransaction(); // save the student object System.out.println("Saving the student"); session.save(theStudent); // commit transaction tx.commit(); //OR // session.getTransaction().commit(); // either of them will work System.out.println("Done"); }finally { factory.close(); } } } 3. Run the application and verify in mysql ----------------------------------------------------------------------------------- Hibernate Object Life LifeCycle ====================================== - Hibernate saves, update and delete record in the database table regarding to value of object as your persistent class is associated with the database table. In Hibernate, either we create an object of an entity and save it into the database, or we fetch the data of an entity from the database. Here, each entity is associated with the lifecycle. The entity object passes through the different stages of the lifecycle. - 4 states are there 1. Transient 2. Persistent 3. Detached 4. Removed New instance of Entity / new state --------------------> Transient >---------------------- | save() | ^ | | saveOrUpdate() | | delete() | | persist() | | | | update() | | | | v | v get() |-------------------------> Persistent Garbage/Removed load() | ^ update() ^ find() detach()| | save() | iterate() * clear() | | saveOrUpdate() | scroll() * close() | | merge() | uniqueResult() evict() | | lock() |remove() v | replicate() | Detached ------------------------ * affects all instances in a session every methods will be called by session object, session.get(), session.load() ...etc Transient State ------------------------ - The transient state is the initial state of an object. - Once we create an instance of POJO class, then the object entered in the transient state. - Here, an object is not associated with the Session. So, the transient state is not related to any database. - Hence, modifications in the data don't affect any changes in the database.' - The transient objects exist in the heap memory. They are independent of Hibernate. Student theStudent = new Student(); // Here, object enters in the transient state. theStudent.setId(101); theStudent.setFirstname("Debi"); theStudent.setLastName("Mishra"); Persistent State -------------------------- - As soon as the object associated with the Session, it entered in the persistent state. - Hence, we can say that an object is in the persistence state when we save or persist it. - Here, each object represents the row of the database table. - So, modifications in the data make changes in the database. Session session = sessionFactory.openSession(); // Transient state. Student theStudent = new Student(); // Persistent state. Hibernate will the employee object to the database. session.saveOrUpdate(emp); // Modification is automatically saved because the employee object is in persistent state. theStudent.setFirstName("Debi Prasad"); // Commit the transaction. session.getTransaction().commit(); Detached State -------------------------- - Once we either close the session or clear its cache, then the object entered into the detached state. - As an object is no more associated with the Session, modifications in the data don't affect any changes in the database.' - However, the detached object still has a representation in the database. - If we want to persist the changes made to a detached object, it is required to reattach the application to a valid Hibernate session. - To associate the detached object with the new hibernate session, use any of these methods - load(), merge(), refresh(), update() or save() on a new session with the reference of the detached object. // All the objects will be in the detached state after the execution of this line. session.close(); Removed State ---------------------- - When the persistent object is deleted from the database, it is passed to the session’s delete(obj) method. - At this state, java instance exists but any changes made to the object are not saved to the database. - Developers can use the session.delete(obj) method to remove the database record and will no longer manage the pojo object. // Removes a persistent instance from the datastore. session.delete(obj); // Removes a Detached instance from the datastore. session.remove(obj); Wrap-Up ------------- - Newly created pojo objects will be in the Transient state - Persistent objects represent one row of the database table and are always associated with some unique hibernate session - Detached objects are those that have left the union with the session object - Removed objects are those that have been passed to the session’s delete(obj) method https://www.youtube.com/watch?v=kZpRyEABnms https://www.youtube.com/watch?v=T02FicxK_aY ************************************************ Give Error ------------------- MySQL Dialect Error - Dialect is the language used by the database for communication. It varies from database to database. For instance, the syntax of the queries for MySQL differs from Oracle. Hibernate needs to know the language in which it need to generate or translate the HQL to the corresponding native query for execution. In console it shows error as CommandAcceptanceException: Error executing DDL via JDBC Statement while writing hql Query it writes Create table employee ( id INT Primary Key Auto_increment, empname varchar(45) default null )type=MyISAM; which is not supported in latest version of mysql, was supported before 5.5.0 - Instead of type it should be ENGINE Create table employee ( id INT Primary Key Auto_increment, empname varchar(45) default null )ENGINE=MyISAM; : engine=InnoDB org.hibernate.dialect.MySQL5Dialect : engine=MyISAM // USE THIS org.hibernate.dialect.MySQL8Dialect : engine=InnoDB org.hibernate.dialect.MySQLMyISAMDialect : type=MyISAM org.hibernate.dialect.MySQLDialect : type=MyISAM and increase connection.pool_size 2 ************************************************************* Do this -------------------- 1. Copy and paste and rename 1_Hibernate_Demo to 2_Hibernate_Lifecycle 2. hibernate.cfg.xml com.mysql.cj.jdbc.Driver jdbc:mysql://localhost:3306/hb_student_tracker?useSSL=false&serverTimezone=UTC hibernate hibernate 2 org.hibernate.dialect.MySQL5Dialect true true thread update 3. Employee.java class package demo.entity; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Table; import javax.persistence.Id; //@SuppressWarnings("deprecation") @Entity //@org.hibernate.annotations.Entity(selectBeforeUpdate = true) //Optional, if there is any update before next session / if any setter method is called with Entity class object @Table(name="employee") public class Employee { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name="id") private int Id; @Column(name="empname") private String empName; public Employee() { } public Employee(String empName) { super(); this.empName = empName; } public int getId() { return Id; } public void setId(int id) { Id = id; } public String getEmpName() { return empName; } public void setEmpName(String empName) { this.empName = empName; } @Override public String toString() { return "Employee [Id=" + Id + ", empName=" + empName + "]"; } @Override public void finalize() { } } 4. EmployeeDemo.java calss package demo.application; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Employee; public class EmployeeDemo { public static void main(String[] args) { SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Employee.class).buildSessionFactory(); Session session = factory.openSession(); try { Transaction tx = session.beginTransaction(); // Transient State (emp) Employee emp = new Employee("Rog"); emp.setEmpName("Debi"); // Persistent State (emp) session.save(emp); emp.setEmpName("Debi Vicky"); emp.setEmpName("Debi Prasad"); tx.commit(); session.close(); // after this emp is a Detached object, no link between Entity and session emp.setEmpName("Vicky"); //won't be reflected in database emp.finalize(); //Calling explicitly the finalize method emp = null; System.gc(); //Requesting JVM to call garbage collector // emp is in Removed State }finally { factory.close(); } } } 5. EmployeeDemoNext.java class package demo.application; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Employee; public class EmployeeDemoNext { public static void main(String[] args) { SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Employee.class).buildSessionFactory(); try { Session session1 = factory.openSession(); Transaction tx = session1.beginTransaction(); Employee emp = session1.get(Employee.class, 1); // emp in persistent state tx.commit(); session1.close(); // emp in Detached state emp.setEmpName("Vicky"); Session session2 = factory.openSession(); Transaction tx2 = session2.beginTransaction(); session2.merge(emp); // emp in Persistent state // emp.setEmpName("Vickysh"); tx2.commit(); session2.close(); // emp in Detached state emp.finalize(); //Calling explicitly the finalize method emp = null; System.gc(); //Requesting JVM to call garbage collector // emp is in Removed State }finally { factory.close(); } } } 6. Run EmployeeDemo.java then change hbm2ddl.auto to update and run EmployeeDemoNext.java ------------------------------------------------------------------------------------------------------ Hibernate and Primary Keys ========================================== Primary Key - uniquely identifies each row in a table - must be a unique value - can not contain null values @GeneratedValue(strategy = GenerationType.IDENTITY) GenerationType.AUTO : Pick an appripriate strategy for the particular database GenerationType.IDENTITY : Assign primary keys using database identity column GenerationType.SEQUENCE : Assign primary keys using a database sequence GenerationType.TABLE : Assign primary keys using an underlying database table to ensure uniqueness *** - To define you own custom generation strategy 1. Create implementation of org.hibernate.id.IdentifierGenerator 2. Override the method : public Serializable generate() Do this ------------------ 1. In 1_Hibernate_Demo create a PrimaryKeyDemo.java class and do the changes in Student.java package demo.application; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Student; // In POJO Student.java class @GeneratedValue(strategy = GenerationType.IDENTITY) added over Id public class PrimaryKeyDemo { public static void main(String[] args) { SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Student.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { // Create 3 Student objects System.out.println("Creating 3 Student objects"); Student theStudent1 = new Student("Debi Prasad", "Mishra", "debiprasad@gmail.com"); Student theStudent2 = new Student("Debi", "Mishra", "debi@gmail.com"); Student theStudent3 = new Student("Debi", "Vicky", "debi1234@gmail.com"); // start the transaction Transaction tx = session.beginTransaction(); // save the student object System.out.println("Saving the students"); session.save(theStudent1); session.save(theStudent2); session.save(theStudent3); tx.commit(); System.out.println("Done"); }finally { factory.close(); } } } 2. Run the query Alter table student Auto_Increment = 3000; -- New entries will start from 3000 3. Run the PrimaryKeyDemo.java again ----------------------------------------------------------------------------------------------- Retrieve and Object =============================== - You retrieve an object using its primary key // save an object Student theStudent1 = new Student("Debi Prasad", "Mishra", "debiprasad@gmail.com"); session.save(theStudent1); // retrieve an object Student myStudent = session.get(Student.class, theStudent.getId()); - If it founds the object from the database, it will return the object else it will return null. Do this ------------------ 1. In 1_Hibernate_Demo Create StudentFetchDemo.java class package demo.application; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Student; public class StudentFetchDemo { public static void main(String[] args) { // create a session factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Student.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { // Create a Student object System.out.println("Creating a new student object"); Student theStudent = new Student("Vicky Rog", "Mishra", "debiprasad@gmail.com"); // start the transaction Transaction tx = session.beginTransaction(); // save the student object System.out.println("Saving the student"); System.out.println(theStudent); session.save(theStudent); // commit transaction tx.commit(); //OR // ============================================================================= // My New Code // find out the student's primary key id System.out.println("Saved Student, Generated Id "+theStudent.getId()); // now get a new session and start a transaction session = factory.getCurrentSession(); Transaction tx1 = session.beginTransaction(); // session.getTransaction().begin(); // Both ways to start a transaction // retrieve the student based on primary key System.out.println("\nGetting student with id : "+theStudent.getId()); Student student = session.get(Student.class, theStudent.getId()); System.out.println("Get Complete : "+student); // commit the transaction tx1.commit(); System.out.println("Done"); }finally { factory.close(); } } } --------------------------------------------------------------------------------------------- Query Objects using Hibernate ====================================== - It uses HQL(Hibernate Query Language). - It is similar to SQL, has the where, like, order by, group by, join ...etc Retrieve all students ------------------------- List students = session.createQuery("from Student").getResultList(); // Student -- Give the pojo class name List students = session.createQuery("from Student s where s.lastName='Mishra'").getResultList(); // lastName is the POJO class object property/variable name Using Predicates -------------------- List students = session.createQuery("from Student s where s.lastName='Mishra'" + "OR s.firstName='Debi'"). getResultList(); List students = session.createQuery("from Student s where " + "s.email LIKE '%gmail.com'").getResultList(); Retireve infos by CriteriaBuilder ------------------------------------------- // Order By amountToPay limit 1 // Query : select amounttopay from manmaytosourav order by id desc limit 1; // ManmayToSourav : POJO Class CriteriaBuilder builder = session.getCriteriaBuilder(); CriteriaQuery criteriaQuery = builder.createQuery(ManmayToSourav.class); Root root = criteriaQuery.from(ManmayToSourav.class); criteriaQuery.select(root); criteriaQuery.orderBy(builder.desc(root.get("id"))); Query query = session.createQuery(criteriaQuery); query.setMaxResults(1); List resultList = query.getResultList(); If you are using Hibernate 5.2 or higher, then the Query list() method has been deprecated. Replace session.createQuery("from Student").list() With session.createQuery("from Student").getResultList() Do this ---------------------- 1. In 1_Hibernate_Demo create QueryStudentDemo.java class package demo.application; import java.util.List; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Student; public class QueryStudentDemo { public static void main(String[] args) { // create a session factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Student.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { // start the transaction Transaction tx = session.beginTransaction(); // query the students // List students = session.createQuery("from Student").getResultList(); // List students = session.createQuery("from Student s where s.lastName = 'Mishra'").getResultList(); // List students = session.createQuery("from Student s where s.lastName = 'Mishra'" + " OR s.firstName = 'Vicky'").getResultList(); List students = session.createQuery("from Student s where" + " s.email LIKE '%gmail.com'").getResultList(); // % wild-card parameter : ends with gmail.com //display the students for (Student student : students) { System.out.println(student); } // commit transaction tx.commit(); System.out.println("Done"); }finally { factory.close(); } } } -------------------------------------------------------------------------------------- Update Objects using Hibernate ========================================= int studentId = 1; Student myStudent = session.get(Student.class, studentId) ; // Update the name to "Rog" myStudent.setFirstName("Rog"); // commit the transaction session.getTransaction().commit(); // OR tx.commit() - No need to explicitely save because after retrieving it is in persistent object Update for all Students ------------------------------- sesssion.createQuery("update Student set email=foo@gmail.com").executeUpdate(); Do this ------------------- 1. In 1_Hibernate_Demo create UpdateStudentDemo.java class package demo.application; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Student; public class UpdateStudentDemo { public static void main(String[] args) { // create a session factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Student.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { Transaction tx = session.beginTransaction(); // session.getTransaction().begin(); // Both ways to start a transaction int studentId = 1; // retrieve the student based on primary key : id System.out.println("\nGetting student with id : "+studentId); Student student = session.get(Student.class, studentId); System.out.println("Updating Student"); student.setFirstName("Rog Vicky"); // commit the transaction tx.commit(); // NEW CODE session = factory.getCurrentSession(); session.beginTransaction(); // Update Email for everyone System.out.println("Updating email for all students"); session.createQuery("update Student set email = 'debiprasadmishra50@gmail.com'").executeUpdate(); session.getTransaction().commit(); System.out.println("Done"); }finally { factory.close(); } } } --------------------------------------------------------------------------------- Deleting Objects using Hibernate ========================================== int studentId = 1; Student myStudent = session.get(Student.class, studentId) ; // delete the student session.delete(myStudent); // commit the transaction session.getTransaction().commit(); // OR tx.commit() Using HQL ------------------ session.createQuery("delete from Student where id = 2").executeUpdate(); Do this ---------------- 1. In 1_Hibernate_Demo create DeleteStudentDemo.java package demo.application; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Student; public class DeleteStudentDemo { public static void main(String[] args) { // create a session factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Student.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { Transaction tx = session.beginTransaction(); // session.getTransaction().begin(); // Both ways to start a transaction int studentId = 1; // retrieve the student based on primary key : id System.out.println("\nGetting student with id : "+studentId); Student student = session.get(Student.class, studentId); // delete the student System.out.println("Deleting Student : "+student); session.delete(student); // Either use HQL or delete() way // delete student with id = 2 using HQL System.out.println("Deleting student id = 2"); session.createQuery("delete from Student where id = 2").executeUpdate(); // commit the transaction tx.commit(); System.out.println("Done"); }finally { factory.close(); } } } ------------------------------------------------------------------------------------ How to read Dates with Hibernate ========================================= 1. Alter database table for student 2. Add a date utils class for parsing and formatting dates 3. Add date field to Student class 4. Add toString method to Student class 5. Update CreateStudentDemo 1. Alter database table for student ALTER TABLE `hb_student_tracker`.`student` ADD COLUMN `date_of_birth` DATETIME NULL AFTER `last_name`; 2. Add a date utils class for parsing and formatting dates package demo.application; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class DateUtils { // The date formatter // - dd: day in month (number) // - MM: month in year (number) // - yyyy: year // // See this link for details: https://docs.oracle.com/javase/tutorial/i18n/format/simpleDateFormat.html // // private static SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy"); // read a date string and parse/convert to a date public static Date parseDate(String dateStr) throws ParseException { Date theDate = formatter.parse(dateStr); return theDate; } // read a date and format/convert to a string public static String formatDate(Date theDate) { String result = null; if (theDate != null) { result = formatter.format(theDate); } return result; } } 3. Add date field to Student class and generate getter and setters and update constructor using this field too @Column(name="date_of_birth") @Temporal(TemporalType.DATE) private Date dateOfBirth; 4. Add toString method to Student class @Override public String toString() { return "Student [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", email=" + email + ", dateOfBirth=" + DateUtils.formatDate(dateOfBirth) + "]"; } 5. Update CreateStudentDemo package com.luv2code.hibernate.demo; import java.text.ParseException; import java.util.Date; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import com.luv2code.hibernate.demo.entity.Student; public class CreateStudentDemo { public static void main(String[] args) { // create session factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Student.class) .buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { // create a student object System.out.println("creating a new student object ..."); String theDateOfBirthStr = "31/12/1998"; Date theDateOfBirth = DateUtils.parseDate(theDateOfBirthStr); Student tempStudent = new Student("Pauly", "Doe", "paul@luv.com", theDateOfBirth); // start transaction session.beginTransaction(); // save the student object System.out.println("Saving the student ..."); session.save(tempStudent); // commit transaction session.getTransaction().commit(); System.out.println("Success!"); } catch (Exception exc) { exc.printStackTrace(); } finally { factory.close(); } } } =========================================================================================================== Creating a Hibernate Project ============================================= - It can happen in 3 ways 1. With hibernate.cfg.xml : configuration file 2. Using Hibernate API : setProperty() 3. Using Properties File : hibernate.properties 4. Using Properties Class 2. Using Hibernate API : setProperty() ----------------------------------------------- package demo.creation; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; public class WithoutXML { private static SessionFactory getSessionFactory() { // create configuration using hibernate API Configuration configuration = new Configuration(); configuration.setProperty("connection.driver_class", "com.mysql.cj.jdbc.Driver"); configuration.setProperty("hibernate.connection.url", "jdbc:mysql://localhost/test"); configuration.setProperty("hibernate.connection.username", "root"); configuration.setProperty("hibernate.connection.password", "mysql"); configuration.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect"); configuration.setProperty("current_session_context_class", "thread"); configuration.setProperty("show_sql", "true"); configuration.setProperty("format_sql", "true"); configuration.setProperty("format_sql", "true"); configuration.setProperty("connection.pool_size", "1"); configuration.setProperty("hbm2ddl.auto", "update"); return configuration.buildSessionFactory(); } public static void main(String[] args) { // getting session factory SessionFactory sessionFactory = getSessionFactory(); System.out.println("Session factory object created : " + sessionFactory); Session session = sessionFactory.openSession(); try { System.out.println("Session object created : " + session); Transaction tx = session.beginTransaction(); // We can use this session object for doing CRUD (inserting, // updating and deleting rows) tx.commit(); } catch (Exception e) { e.printStackTrace(); } finally { session.close(); } } } 4. Using Properties Class --------------------------------- package demo.creation; import java.util.Properties; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; import org.hibernate.service.ServiceRegistry; import demo.entity.Student; public class WithoutXMLPropertiesClass { private static SessionFactory factory; public static void getSessionFactory() { if (factory == null) { try { Configuration configuration = new Configuration(); // Hibernate settings equivalent to hibernate.cfg.xml's properties Properties settings = new Properties(); settings.put(Environment.DRIVER, "com.mysql.cj.jdbc.Driver"); settings.put(Environment.URL, "jdbc:mysql://localhost:3306/hibernate_db?useSSL=false"); settings.put(Environment.USER, "root"); settings.put(Environment.PASS, "root"); settings.put(Environment.DIALECT, "org.hibernate.dialect.MySQL5Dialect"); settings.put(Environment.SHOW_SQL, "true"); settings.put(Environment.CURRENT_SESSION_CONTEXT_CLASS, "thread"); settings.put(Environment.HBM2DDL_AUTO, "create-drop"); configuration.setProperties(settings); configuration.addAnnotatedClass(Student.class); ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build(); factory = configuration.buildSessionFactory(serviceRegistry); Session session = factory.getCurrentSession(); Transaction tx = session.beginTransaction(); // Here do your CRUD business tx.commit(); } catch (Exception e) { e.printStackTrace(); } } } } ============================================================================================== Creating factory, session, transaction in different Types ==================================================================== package demo.creation; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Student; public class Creation { public static void main(String[] args) { // Creating the factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Student.class).buildSessionFactory(); Configuration cfg = new Configuration(); cfg.configure("hibernate.cfg.xml"); //we can simply say cfg.configure() and it will look for the file in your classpath by default cfg.addAnnotatedClass(Student.class); // either add the mapping in cfg file else do this SessionFactory factory1 = cfg.buildSessionFactory(); // Opening a Session Session session = factory.openSession(); // Manual closing Session session2 = factory.getCurrentSession(); // Auto closing // Beginning/Starting a transaction session.getTransaction().begin(); Transaction tx = session.beginTransaction(); // Committing a transaction tx.commit(); session.getTransaction().commit(); // Creating a Transaction Directly Transaction transaction = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Student.class).buildSessionFactory().getCurrentSession().beginTransaction(); transaction.commit(); } } ================================================================================================================= *************************************************************************************************************** Hibernate LifeCycle Interchange ============================================= 1. Hibernate_LifeCycle_Interchange Created 2. hibernate.cfg.xml ---------------------------- com.mysql.cj.jdbc.Driver jdbc:mysql://localhost:3306/hb_student_tracker?useSSL=false&serverTimezone=UTC hibernate hibernate 2 org.hibernate.dialect.MySQL5Dialect true true thread create 3. Employee.java : Entity Class / POJO Class ------------------------------------------------- package demo.entity; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "employee") public class Employee { @Id // @GeneratedValue(strategy = GenerationType.AUTO) @GeneratedValue(strategy = GenerationType.IDENTITY) // @org.hibernate.annotations.Entity(selectBeforeUpdate = true) //Optional, if there is any update before next session / if any setter method is called with Entity class object private int id; @Column(name = "empName") private String empName; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getEmpName() { return empName; } public void setEmpName(String empName) { this.empName = empName; } @Override public String toString() { return "Employee [id=" + id + ", empName=" + empName + "]"; } public Employee(String empName) { super(); this.empName = empName; } public Employee() { } @Override public void finalize() { } } 4. EmployeeDemo.java ---------------------------- package demo.application; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Employee; // Transient --> Persistent --> Detached --> Removed public class EmployeeDemo { public static void main(String[] args) { // Create a factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Employee.class).buildSessionFactory(); // Create a session Session session = factory.getCurrentSession(); try { // Begin Transaction Transaction tx = session.beginTransaction(); Employee emp = new Employee("Debi"); // emp in Transient state System.out.println("\nEmployee : "+emp); emp.setEmpName("Debi Prasad"); System.out.println("\nEmployee : "+emp); session.save(emp); // emp in Persistent State emp.setEmpName("Vicky"); // If emp is in Persistent State, no need to save() again, It will update in DB System.out.println("\nEmployee : "+emp); tx.commit(); session.close(); // emp in Detached State emp.setEmpName("Debi Mishra"); // Not gonna be reflected in DB System.out.println("\nEmployee : "+emp); emp.finalize(); emp=null; System.gc(); // emp in Removed State }finally { factory.close(); } } } 5. EmployeeDemo2.java --------------------------- package demo.application; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Employee; // Persistent --> Detached --> Persistent --> Detached --> Removed but will reflect as a new Object in DB as close() affects all instances public class EmployeeDemo2 { public static void main(String[] args) { SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Employee.class).buildSessionFactory(); try { Session session1 = factory.getCurrentSession(); Transaction tx1 = session1.beginTransaction(); Employee emp = session1.get(Employee.class, 1); // emp in Persistent State System.out.println("\nEmployee : "+emp); tx1.commit(); session1.close(); // emp in Detached State emp.setEmpName("Debi"); // not reflected in DB System.out.println("\nEmployee : "+emp); Session session2 = factory.getCurrentSession(); Transaction tx2 = session2.beginTransaction(); session2.save(emp); // Persistent State // now changes will be reflected in DB but as a new object // To resolve, use @org.hibernate.annotations.Entity(selectBeforeUpdate = true) in POJO class // Or use detach() to stay in next method, Refer EmployeeDemo3.java tx2.commit(); emp.finalize(); emp=null; System.gc(); // emp in Removed State }finally { factory.close(); } } } 6. EmployeeDemo3.java ----------------------------- package demo.application; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Employee; // Persistent --> Detached --> Persistent --> Detached --> Removed public class EmployeeDemo3 { public static void main(String[] args) { SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Employee.class).buildSessionFactory(); try { Session session = factory.getCurrentSession(); Transaction tx = session.beginTransaction(); Employee emp = session.get(Employee.class, 1); // emp in Persistent State System.out.println("\nEmployee : "+emp); session.detach(emp); // emp in Detached State emp.setEmpName("Debi Prasad"); // not reflected in DB System.out.println("\nEmployee : "+emp); session.update(emp); // Persistent State tx.commit(); session.close(); // Detached State emp.finalize(); emp=null; System.gc(); // emp in Removed State }finally { factory.close(); } } } 7. EmployeeDemo4.java --------------------------------- package demo.application; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Employee; // Transient --> Persistent --> Transient --> Removed public class EmployeeDemo4 { public static void main(String[] args) { SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Employee.class).buildSessionFactory(); try { Session session = factory.getCurrentSession(); Transaction tx = session.beginTransaction(); Employee emp = new Employee("Debi"); // emp in Transient State System.out.println("\nEmployee : "+emp); session.save(emp); // emp in Persistent State session.delete(emp); // emp in Transient State System.out.println("\nEmployee : "+emp); tx.commit(); emp.finalize(); emp=null; System.gc(); // emp in Removed State }finally { factory.close(); } } } 8. EmployeeDemo5.java -------------------------------- package demo.application; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Employee; // Transient --> Persistent --> Detached --> Persistent --> Transient --> Removed public class EmployeeDemo5 { public static void main(String[] args) { SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Employee.class).buildSessionFactory(); try { Session session = factory.getCurrentSession(); Transaction tx = session.beginTransaction(); Employee emp = new Employee("Debi"); // emp in Transient State System.out.println("\nEmployee : "+emp); session.save(emp); // emp in Persistent State session.detach(emp); // emp in Detached State // emp = session.get(Employee.class, emp.getId()); // emp in Persistent State session.saveOrUpdate(emp); // Applicable // session.merge(emp); // Not applicable // Error session.delete(emp); // emp in Transient State tx.commit(); System.out.println("\nEmployee : "+emp); emp.finalize(); emp = null; System.gc(); // emp in Removed State }finally { factory.close(); } } } ************************************************************************************************************* Hibernate Mapping ========================= 1. One to One 2. One to Many , Many to One 3. Many to Many Cascade Types --------------------- Persist : If the entity is persisted/saved , related entity will also be persisted. Remove : If the entity is removed/deleted, related entity will also be deleted Refresh : If entity is refreshed, related entity will also be refreshed Detach : If entity is detached(not associated with the session), then related entity will also be detached Merge : If entity is merged, then related entity will also be merged All : All of the above cascade types will be executed Configure : @OneToOne(cascade = CascadeType.ALL) - By default no operations are cascaded Configuring Multiple Types : @OneToOne(cascade = {CascadeType.DETACH,CascadeType.PERSIST,CascadeType.REMOVE}) 1. One to One (Uni-Directional) ================================================ - Instructor --> InstructorDetails - Key infos of a instructor are in 2 separate tables Configure : public class Instructor { @OneToOne @JoinColumn(name = instructor_detail_id) private InstructorDetail instructorDetail; // instructor_detail_id in instructor is foreign key to id in instructor_detail // It will go to the instructor_detail, look for the Primary Key and will perform a foreign key } Development Process ------------------------ 1. Defining our Database Tables 2. Create InstructorDetail class 3. Create Instructor class 4. Create Main class 1. Defining our Database Tables ------------------------------------- - tables are instructor_detail instructor instructor_detail ---------------------- create table instructor_detail ( id int(11) Not Null Auto_Increment Primary Key, youtube_channel varchar(45) Default Null, hobby varchar(45) Default Null ); instructor --------------- create table instructor ( id int(11) Not Null Auto_Increment Primary Key, first_name varchar(45) Default Null, last_name varchar(45) Default Null, email varchar(45) Default Null, instructor_detail_id int(11) Default Null, foreign key (instructor_detail_id) references instructor_detail (id) ); Do this ================== 1. Create 3_Hibernate_Mapping_OneToOne and add the JARs and build path 2. Add the configuration file and create 2 packages named "demo.entity" and "demo.application.unidirectional" hibernate.cfg.xml ------------------------ com.mysql.cj.jdbc.Driver jdbc:mysql://localhost:3306/hibernate_onetoone?useSSL=false&serverTimezone=UTC hibernate hibernate org.hibernate.dialect.MySQL5Dialect true true update 1 thread 3. Create POJO class in demo.entity Package InstructorDetail.java ----------------------------- package demo.entity; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "instructor_detail") public class InstructorDetail { // annotate the class and map it to db table // define the fields // annotate the fields with db column names // create constructors // generate setters and getters // generate toString() method @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private int id; @Column(name = "youtube_channel") private String youtubeChannel; @Column(name = "hobby") private String hobby; public InstructorDetail() { } public InstructorDetail(String youtubeChannel, String hobby) { this.youtubeChannel = youtubeChannel; this.hobby = hobby; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getYoutubeChannel() { return youtubeChannel; } public void setYoutubeChannel(String youtubeChannel) { this.youtubeChannel = youtubeChannel; } public String getHobby() { return hobby; } public void setHobby(String hobby) { this.hobby = hobby; } @Override public String toString() { return "InstructorDetail [id=" + id + ", youtubeChannel=" + youtubeChannel + ", hobby=" + hobby + "]"; } } Instructor.java ---------------------- package demo.entity; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToOne; import javax.persistence.Table; @Entity @Table(name = "instructor") public class Instructor { // annotate the class and map it to db table // define the fields // annotate the fields with db column names // ** set up mapping to InstructorDetail entity // create constructors // generate setters and getters // generate toString() method @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private int id; @Column(name = "first_name") private String firstName; @Column(name = "last_name") private String lastName; @Column(name = "email") private String email; @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name = "instructor_detail_id") private InstructorDetail instructorDetail; // create a column : instructor_detail_id, add foreign key to it with instructor_detail tables id(primary Key) column public Instructor() { } public Instructor(String firstName, String lastName, String email) { this.firstName = firstName; this.lastName = lastName; this.email = email; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public InstructorDetail getInstructorDetail() { return instructorDetail; } public void setInstructorDetail(InstructorDetail instructorDetail) { this.instructorDetail = instructorDetail; } @Override public String toString() { return "Instructor [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", email=" + email + ", instructorDetail=" + instructorDetail + "]"; } } 4. Create InstructorCreateDemo.java ----------------------------------------- package demo.application; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Instructor; import demo.entity.InstructorDetail; public class InstructorCreateDemo { public static void main(String[] args) { // create a factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Instructor.class).addAnnotatedClass(InstructorDetail.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { // create the objects /* Instructor instructor = new Instructor("Debi", "Mishra", "debi@gmail.com"); InstructorDetail instructorDetail = new InstructorDetail("www.debi.com/youtube", "To Do Everything"); */ Instructor instructor = new Instructor("Debi Prasad", "Vicky", "debivicky@gmail.com"); InstructorDetail instructorDetail = new InstructorDetail("www.debivicky.com/youtube", "To Do Nothing"); // associate the objects together instructor.setInstructorDetail(instructorDetail); // start a transaction Transaction tx = session.beginTransaction(); System.out.println("Saving Instructor : "+instructor); System.out.println("Saving InstructorDetail : "+instructorDetail); // Save the Instructor session.save(instructor); // Note : this will also save the details of InstructorDetail because of CascadeType.ALL //commit transaction tx.commit(); System.out.println("Done"); }finally { factory.close(); } } } 5. Create InstructorDeleteDemo.java ----------------------------------------------- package demo.application; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Instructor; import demo.entity.InstructorDetail; public class InstructorDeleteDemo { public static void main(String[] args) { // create a factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Instructor.class).addAnnotatedClass(InstructorDetail.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { // start a transaction Transaction tx = session.beginTransaction(); // get the instructor by their primary key / id int id = 2; // Id 2 data will be deleted Instructor instructor = session.get(Instructor.class, id); System.out.println("Found Instructor : "+instructor); // Delete the instructors if(instructor != null) { System.out.println("Deleting: "+instructor); session.delete(instructor); // Note: This will also delete associated "details" object in the instructor_detail table because of the Cascade } //commit transaction tx.commit(); System.out.println("Done"); }finally { factory.close(); } } } ---------------------------------------------------------------------------------------------- 1. One to One (Bi-Directional) ================================================ - In Uni-Directional we can only proceed through Instructor, Not From InstructorDetail - In Bi-Directional we can begin from any one of them - No changes required with the existing Database Schema/Table Development Process ------------------------ 1. Add a new field to the Instructor to InstructorDetail and generate ***getter and setters private Instructor instructor; 2. Add @OneToOne Annotation @OneToOne(mappedBy = instructorDetail, cascade = CascadeType.ALL) // Refers to instructorDetail field in the Instructor Class private Instructor instructor; - mappedBy : Use the information from Instructor class @JoinColumn to help find associated instructor Do this ---------------------- 1. In 3_Hibernate_Mapping_OneToOne In POJO class InstructorDetail.java do the changes --------------------------------------------------------------------------------------------------------- package demo.entity; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToOne; import javax.persistence.Table; @Entity @Table(name = "instructor_detail") public class InstructorDetail { // annotate the class and map it to db table // define the fields // annotate the fields with db column names // create constructors // generate setters and getters // generate toString() method @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private int id; @Column(name = "youtube_channel") private String youtubeChannel; @Column(name = "hobby") private String hobby; //============================================================================================= //** For Bi-directional Add the private Instructor instructor and generate getter and setters and use the @OneToOne(mappedBy = instructorDetail) @OneToOne(mappedBy = "instructorDetail", cascade = CascadeType.ALL) private Instructor instructor; public Instructor getInstructor() { return instructor; } public void setInstructor(Instructor instructor) { this.instructor = instructor; } //============================================================================================= // Constructor public InstructorDetail() { } public InstructorDetail(String youtubeChannel, String hobby) { this.youtubeChannel = youtubeChannel; this.hobby = hobby; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getYoutubeChannel() { return youtubeChannel; } public void setYoutubeChannel(String youtubeChannel) { this.youtubeChannel = youtubeChannel; } public String getHobby() { return hobby; } public void setHobby(String hobby) { this.hobby = hobby; } @Override public String toString() { return "InstructorDetail [id=" + id + ", youtubeChannel=" + youtubeChannel + ", hobby=" + hobby + "]"; } } 2. Create a package demo.application.Bi_directional and create InstructorBiDirectionalDemo.java --------------------------------------------------------------------------------------------------------- package demo.application.Bi_directional; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Instructor; import demo.entity.InstructorDetail; public class InstructorBiDirectionalDemo { public static void main(String[] args) { // create a factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Instructor.class).addAnnotatedClass(InstructorDetail.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { // start a transaction Transaction tx = session.beginTransaction(); // get the instructor detail object int id = 1; // will get the Instructor with id of 1 InstructorDetail instructorDetail = session.get(InstructorDetail.class, id); // print instructor detail System.out.println("InstructorDetail : "+instructorDetail); // print associated instructor System.out.println("Instructor : "+instructorDetail.getInstructor()); //commit transaction tx.commit(); System.out.println("Done"); }catch (NullPointerException e) { e.printStackTrace(); System.out.println("No Instructor Found"); } finally { session.close(); factory.close(); } } } 3. create InstructorDeleteBiDirectionalDemo.java ------------------------------------------------------- package demo.application.Bi_directional; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Instructor; import demo.entity.InstructorDetail; public class InstructorDeleteBiDirectionalDemo { public static void main(String[] args) { // create a factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Instructor.class).addAnnotatedClass(InstructorDetail.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { // start a transaction Transaction tx = session.beginTransaction(); // get the instructor detail object int id = 3; // will get the Instructor with id of 3 InstructorDetail instructorDetail = session.get(InstructorDetail.class, id); // print instructor detail System.out.println("InstructorDetail : "+instructorDetail); // print associated instructor System.out.println("Instructor : "+instructorDetail.getInstructor()); // ===================================================================================== // delete the instructor detail System.out.println("Deleting : "+instructorDetail); session.delete(instructorDetail); // ===================================================================================== //commit transaction tx.commit(); System.out.println("Done"); }catch (NullPointerException e) { e.printStackTrace(); System.out.println("No Instructor Found"); } finally { session.close(); factory.close(); } } } ********* ------------------------------------------------------------------------------------------------------------- NOTE: 1. During Deletion if you wanna keep the Instructor but not the InstructorDetail then Modify the CascadeType on private Instructor instructor ; Use Everything except the CascadeType.REMOVE 2. Break the bi-directional Link , Remove the associated object reference // delete the instructor detail System.out.println("Deleting : "+instructorDetail); // break the bi-directional link instructorDetail.getInstructor().setInstructorDetail(null); session.delete(instructorDetail); 3. Run the application ------------------------------------------------------------------------------------------------------------- 2. One to Many (Bi-Directional) and Many to One ======================================================== - One Instructor can have many Courses - Many courses can have One Instructor - If you delete an Instructor, do not delete the Course - If you delete the Course, do not delete the Instructor - Basically says that do not use CascadeType.REMOVE Course Table ------------------- Create table course ( id int(11) Not Null Auto_Increment Primary Key, title varchar(45) Unique Default Null, instructor_id int(11) Default Null, foreign key instructor_id references instructor (id) ); Instructor Table ------------------- create table instructor ( id int(11) Not Null Auto_Increment Primary Key, first_name varchar(45) Default Null, last_name varchar(45) Default Null, email varchar(45) Default Null, instructor_detail_id int(11) Default Null, foreign key instructor_detail_id references instructor_detail (id) ); Course Class ------------------- public class Course { @ManyToOne // Many courses can have one instructor @JoinColumn(name = "instructor_id") // create a column instructor_id and add foreign key with instructor tables id(primary key) column private Instructor instructor; } // generate constructors, getters and setters Instructor Class --------------------- public class Instructor { @OneToMany(mappedBy = instructor) // One instructor can have many courses private List courses; //generate getters and setters } mappedBy : Refers to the private Instructor instructor; property in the Course Class *** Add all the cascade types except the CascadeType.REMOVE in both Course and Instructor Class Do this ------------------ 1. Create a new database hibernate_onetomany in mysql and use that 2. Create 4_Hibernate_Mapping_OneToMany and add the JARs and the packages demo.entity and demo.application 3. Update the database name in the configuration file com.mysql.cj.jdbc.Driver jdbc:mysql://localhost:3306/hibernate_onetomany?useSSL=false&serverTimezone=UTC hibernate hibernate org.hibernate.dialect.MySQL5Dialect true true update 1 thread 4. Create the entity classes in demo.entity package InstructorDetail.java --------------------------- package demo.entity; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToOne; import javax.persistence.Table; @Entity @Table(name = "instructor_detail") public class InstructorDetail { // annotate the class and map it to db table // define the fields // annotate the fields with db column names // create constructors // generate setters and getters // generate toString() method @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private int id; @Column(name = "youtube_channel") private String youtubeChannel; @Column(name = "hobby") private String hobby; //============================================================================================= //** For Bi-directional Add the private Instructor instructor and generate getter and setters and use the @OneToOne(mappedBy = instructorDetail) @OneToOne(mappedBy = "instructorDetail", cascade = CascadeType.ALL) private Instructor instructor; public Instructor getInstructor() { return instructor; } public void setInstructor(Instructor instructor) { this.instructor = instructor; } //============================================================================================= // Constructor public InstructorDetail() { } public InstructorDetail(String youtubeChannel, String hobby) { this.youtubeChannel = youtubeChannel; this.hobby = hobby; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getYoutubeChannel() { return youtubeChannel; } public void setYoutubeChannel(String youtubeChannel) { this.youtubeChannel = youtubeChannel; } public String getHobby() { return hobby; } public void setHobby(String hobby) { this.hobby = hobby; } @Override public String toString() { return "InstructorDetail [id=" + id + ", youtubeChannel=" + youtubeChannel + ", hobby=" + hobby + "]"; } } Instructor.java --------------------- package demo.entity; import java.util.ArrayList; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.Table; @Entity @Table(name = "instructor") public class Instructor { // annotate the class and map it to db table // define the fields // annotate the fields with db column names // ** set up mapping to InstructorDetail entity // create constructors // generate setters and getters // generate toString() method @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private int id; @Column(name = "first_name") private String firstName; @Column(name = "last_name") private String lastName; @Column(name = "email") private String email; @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name = "instructor_detail_id") private InstructorDetail instructorDetail; // create a column : instructor_detail_id, add foreign key to it with instructor_detail tables id column // ================================================================================================= // One Instructor can have Many courses so Mapped By @OneToMany(mappedBy = "instructor", cascade = {CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH}) // refers to the instructor property in the Course Class private List courses; public List getCourses() { return courses; } public void setCourses(List courses) { this.courses = courses; } // ================================================================================================= public Instructor() { } public Instructor(String firstName, String lastName, String email) { this.firstName = firstName; this.lastName = lastName; this.email = email; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public InstructorDetail getInstructorDetail() { return instructorDetail; } public void setInstructorDetail(InstructorDetail instructorDetail) { this.instructorDetail = instructorDetail; } @Override public String toString() { return "Instructor [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", email=" + email + ", instructorDetail=" + instructorDetail + "]"; } // =================================================================================== // add convenience methods for bi-directional relationship public void add(Course theCourse) { if(courses == null) { courses = new ArrayList(); } courses.add(theCourse); theCourse.setInstructor(this); } // =================================================================================== } Course.java ------------------- package demo.entity; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; @Entity @Table(name = "course") public class Course { // define the fields, constructors, getters and setters, toString and add the annotation @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private int id; @Column(name = "title") private String title; // Many Courses can have One instructor @ManyToOne(cascade = {CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH}) @JoinColumn(name = "instructor_id") // create a column instructor_id, add foreign key to it with id column of instructor Table private Instructor instructor; public Course() { } public Course(String title) { this.title = title; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public Instructor getInstructor() { return instructor; } public void setInstructor(Instructor instructor) { this.instructor = instructor; } @Override public String toString() { return "Course [id=" + id + ", title=" + title + ", instructor=" + instructor + "]"; } } 5. Add the Instructor to Database, Create InstructorCreateDemo.java package demo.application.BiDirectional; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Course; import demo.entity.Instructor; import demo.entity.InstructorDetail; public class InstructorCreateDemo { public static void main(String[] args) { // create a factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Instructor.class).addAnnotatedClass(InstructorDetail.class).addAnnotatedClass(Course.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { // create the objects Instructor instructor = new Instructor("Debi Prasad", "Mishra", "debimishra@gmail.com"); InstructorDetail instructorDetail = new InstructorDetail("www.debivicky.com/youtube", "To Do Nothing"); // associate the objects together instructor.setInstructorDetail(instructorDetail); // start a transaction Transaction tx = session.beginTransaction(); System.out.println("Saving Instructor : "+instructor); System.out.println("Saving InstructorDetail : "+instructorDetail); // Save the Instructor session.save(instructor); // Note : this will also save the details of InstructorDetail because of CascadeType.ALL //commit transaction tx.commit(); System.out.println("Done"); }finally { session.close(); factory.close(); } } } 6. Create courses and add the courses and insert those, create CourseCreateDemo.java package demo.application.BiDirectional; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Course; import demo.entity.Instructor; import demo.entity.InstructorDetail; public class CourseCreateDemo { public static void main(String[] args) { // create a factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Instructor.class).addAnnotatedClass(InstructorDetail.class).addAnnotatedClass(Course.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { // start a transaction Transaction tx = session.beginTransaction(); // get the instructor from DB int id = 1; // will get the instructor with id 1 from instructor table Instructor instructor = session.get(Instructor.class, id); // create some courses Course course1 = new Course("JAVA SE - Core Java"); Course course2 = new Course("JAVA EE - Advance Java"); // Course course3 = new Course("PHP"); // This is gonna be deleted in future as instructor does not know PHP // add the courses to the instructor instructor.add(course1); instructor.add(course2); // instructor.add(course3); // save the courses session.save(course1); session.save(course2); // session.save(course3); //commit transaction tx.commit(); System.out.println("Done"); }finally { // clean up the resources session.close(); factory.close(); } } } 7. Fetch the Instructor Details, FetchInstructorCourseDemo.java package demo.application.BiDirectional; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Course; import demo.entity.Instructor; import demo.entity.InstructorDetail; public class FetchInstructorCourseDemo { public static void main(String[] args) { // create a factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Instructor.class).addAnnotatedClass(InstructorDetail.class).addAnnotatedClass(Course.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { // start a transaction Transaction tx = session.beginTransaction(); // get the instructor from DB int id = 1; // will get the instructor with id 1 from instructor table Instructor instructor = session.get(Instructor.class, id); System.out.println("Instructor is : "+instructor); // get the courses with the instructor System.out.println("Courses for the Instructor "+instructor.getFirstName()+" are "+instructor.getCourses()); //commit transaction tx.commit(); System.out.println("Done"); }finally { // clean up the resources session.close(); factory.close(); } } } 8. Delete the course, but not the instructor. CourseDeleteDemo.java package demo.application.BiDirectional; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Course; import demo.entity.Instructor; import demo.entity.InstructorDetail; public class CourseDeleteDemo { public static void main(String[] args) { // create a factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Instructor.class).addAnnotatedClass(InstructorDetail.class).addAnnotatedClass(Course.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { // start a transaction Transaction tx = session.beginTransaction(); // get a course int id = 3; // delete the course with id of 3 Course course = session.get(Course.class, id); System.out.println(course); // delete the course session.delete(course); //commit transaction tx.commit(); System.out.println("Done"); }finally { session.close(); factory.close(); } } } =============================================================================================================== Fetch Types ==================== 1. EAGER 2. LAZY - When we retrieve data, should we retrieve everything or not - EAGER - Will retrieve everything - LAZY - Will retrieve data on request - LAZY is preferable using the use-cases and performance issue - while defining the mapping relationship you can give the fetch type public class Instructor { @OneToMany(fetch = FetchType.LAZY, mappedBy = "instructor") private List courses; } - Default Fetch Types : @OneToOne : EAGER @OneToMany : LAZY @ManyToOne : EAGER @ManyToMany : LAZY - For LAZY it requires an open Hibernate session, and requires an connection to retrieve data How to do LAZY loading ------------------------- 1. session.get() and then use the appropriate getter method 2. Using HQL Do this -------------- 1. Copy paste and rename 4_Hibernate_Mapping_OneToMany to 5_Hibernate_DataLoading 2. Copy paste and reanme FetchInstructorCourseDemo to EagerLazyDemo.java 3. In Instructor.java do the changes package demo.entity; import java.util.ArrayList; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.Table; @Entity @Table(name = "instructor") public class Instructor { // annotate the class and map it to db table // define the fields // annotate the fields with db column names // ** set up mapping to InstructorDetail entity // create constructors // generate setters and getters // generate toString() method @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private int id; @Column(name = "first_name") private String firstName; @Column(name = "last_name") private String lastName; @Column(name = "email") private String email; @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name = "instructor_detail_id") private InstructorDetail instructorDetail; // create a column : instructor_detail_id, add foreign key to it with instructor_detail tables id column // ================================================================================================= // One Instructor can have Many courses so Mapped By @OneToMany(fetch = FetchType.LAZY, mappedBy = "instructor", cascade = {CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH}) // refers to the instructor property in the Course Class private List courses; public List getCourses() { return courses; } public void setCourses(List courses) { this.courses = courses; } // ================================================================================================= public Instructor() { } public Instructor(String firstName, String lastName, String email) { this.firstName = firstName; this.lastName = lastName; this.email = email; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public InstructorDetail getInstructorDetail() { return instructorDetail; } public void setInstructorDetail(InstructorDetail instructorDetail) { this.instructorDetail = instructorDetail; } @Override public String toString() { return "Instructor [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", email=" + email + ", instructorDetail=" + instructorDetail + "]"; } // =================================================================================== // add convenience methods for bi-directional relationship public void add(Course theCourse) { if(courses == null) { courses = new ArrayList(); } courses.add(theCourse); theCourse.setInstructor(this); } // =================================================================================== } 4. Perform the operation using LAZY and EAGER For EAGER : It will perform one query and get all the data at once, for getCourses() it will not run another query For LAZY : It will run another select query for getCourses() and display them ===================================================================================================================== 2. One to Many (Uni-Directional) and Many to One ======================================================== Courses will have reviews, a course can have multiple reviews create table review ( id int(11) Primary Key Not Null Auto_Increment, comment varchar(255) Default Null, course_id int(11) Default Null, foreign key course_id references course (id) ); Course Class --------------- public class Course { @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) // one course can have multiple comments @JoinColumn(name = "course_id") // create a column course_id in Review table and add foreign key to id(primary key) of Course table private List reviews; // getter and setters } - If course gets deleted, delete the reviews too - If reviws gets deleted, course stays as it is Do this ------------------------ 1. In 4_Hibernate_Mapping_OneToMany create package demo.application.Uni_Directional 2. In package demo.entity package create Review.java class package demo.entity; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; // Create this table for OneToMany Unidirectional, A Course can have many reviews @Entity @Table(name = "review") public class Review { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private int id; @Column(name = "comment") private String comment; // create the course_id column in Course class public Review() { } public Review(String comment) { this.comment = comment; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getComment() { return comment; } public void setComment(String comment) { this.comment = comment; } @Override public String toString() { return "Review [id=" + id + ", comment=" + comment + "]"; } } 3. Update the Course.java class package demo.entity; import java.util.ArrayList; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.Table; @Entity @Table(name = "course") public class Course { // define the fields, constructors, getters and setters, toString and add the annotation @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private int id; @Column(name = "title") private String title; // Many Courses can have One instructor @ManyToOne(cascade = {CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH}) @JoinColumn(name = "instructor_id") // create a column instructor_id in course table, add foreign key to it with id column of instructor Table private Instructor instructor; // ================================================================================= // Do this for OneToMany Uni-directional, One course can have many reviews @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinColumn(name = "course_id") // create a column course_id in Review table and add foreign key to it with references to id of course table private List reviews; public List getReviews() { return reviews; } public void setReviews(List reviews) { this.reviews = reviews; } // For Adding the reviews to the course public void addReview(Review theReview) { if(reviews == null) { reviews = new ArrayList(); } reviews.add(theReview); } // ================================================================================= public Course() { } public Course(String title) { this.title = title; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public Instructor getInstructor() { return instructor; } public void setInstructor(Instructor instructor) { this.instructor = instructor; } @Override public String toString() { return "Course [id=" + id + ", title=" + title + ", instructor=" + instructor + "]"; } } 4. In demo.application.Uni_Directional package create CreateCourseReviewsDemo.java package demo.application.Uni_Directional; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Course; import demo.entity.Instructor; import demo.entity.InstructorDetail; import demo.entity.Review; public class CreateCourseReviewsDemo { public static void main(String[] args) { // create a factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Instructor.class).addAnnotatedClass(InstructorDetail.class).addAnnotatedClass(Course.class).addAnnotatedClass(Review.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { // start a transaction Transaction tx = session.beginTransaction(); // Create a course Course course = new Course("Hibernate"); // Create the reviews Review review1 = new Review("great course"); Review review2 = new Review("Good explanation"); Review review3 = new Review("Nice delivery"); System.out.println(review1); // add some reviews course.addReview(review1); course.addReview(review2); course.addReview(review3); // save the course ... leverage the CascadeType.ALL to save the reviews too System.out.println("Saving the Course : "+course); System.out.println("Reviews are "+course.getReviews()); session.save(course); //commit transaction tx.commit(); System.out.println("Done"); }finally { // clean up the resources session.close(); factory.close(); } } } 5. Create GetCourseReviewsDemo.java package demo.application.Uni_Directional; import java.util.List; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Course; import demo.entity.Instructor; import demo.entity.InstructorDetail; import demo.entity.Review; public class GetCourseReviewsDemo { public static void main(String[] args) { // create a factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Instructor.class).addAnnotatedClass(InstructorDetail.class).addAnnotatedClass(Course.class).addAnnotatedClass(Review.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { // start a transaction Transaction tx = session.beginTransaction(); // get the course WITH ID 4, print the course, print course reviews int id = 4; Course course = session.get(Course.class, id); System.out.println(course); List reviews = course.getReviews(); for (Review review : reviews) { System.out.println(review); } //commit transaction tx.commit(); System.out.println("Done"); }finally { // clean up the resources session.close(); factory.close(); } } } 6. Create DeleteCourseReviewsDemo.java package demo.application.Uni_Directional; import java.util.List; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Course; import demo.entity.Instructor; import demo.entity.InstructorDetail; import demo.entity.Review; public class DeleteCourseReviewsDemo { public static void main(String[] args) { // create a factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Instructor.class).addAnnotatedClass(InstructorDetail.class).addAnnotatedClass(Course.class).addAnnotatedClass(Review.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { // start a transaction Transaction tx = session.beginTransaction(); // get the course WITH ID 4, print the course, print course reviews int id = 4; Course course = session.get(Course.class, id); System.out.println("Deleting the course and reviews : \n"); System.out.println(course); List reviews = course.getReviews(); for (Review review : reviews) { System.out.println(review); } // delete the course session.delete(course); //commit transaction tx.commit(); System.out.println("Done"); }finally { // clean up the resources session.close(); factory.close(); } } } ======================================================================================================================= Many to Many ================================= - A course can have many students, and a student can have many courses. - Creation of Junction table - Junction Table : Provides mapping between 2 tables Course Course_Student Student ------------ ------------------ ----------- id int |-----------> course_id int ----| id int title Varchar student_id int <--------| first_name Varchar instructor_id int last_name Varchar email Varchar create table course_student( course_id int(11), student_id int(11), Primary Key (course_id, student_id), Foreign Key (course_id) references course (id), Foreign Key (student_id) references student (id) ); In Course class @ManyToMany @JoinTable( name="course_student", joinColumns=@JoinColumn(name="course_id"), // current class inverseJoinColumns=@JoinColumn(name="student_id") // Other Class ) private List students; // getters , setters In Student class @ManyToMany @JoinTable( name="course_student", joinColumns=@JoinColumn(name="student_id"), // current class inverseJoinColumns=@JoinColumn(name="course_id") // Other class ) private List courses; // getters , setters Do this ---------------------- 1. SQL Queries ----------------------- DROP SCHEMA IF EXISTS `hibernate_manytomany`; create database hibernate_manytomany; use hibernate_manytomany; DROP TABLE IF EXISTS `instructor_detail`; CREATE TABLE `instructor_detail` ( `id` int(11) NOT NULL AUTO_INCREMENT, `youtube_channel` varchar(128) DEFAULT NULL, `hobby` varchar(45) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; DROP TABLE IF EXISTS `instructor`; CREATE TABLE `instructor` ( `id` int(11) NOT NULL AUTO_INCREMENT, `first_name` varchar(45) DEFAULT NULL, `last_name` varchar(45) DEFAULT NULL, `email` varchar(45) DEFAULT NULL, `instructor_detail_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `FK_DETAIL_idx` (`instructor_detail_id`), CONSTRAINT `FK_DETAIL` FOREIGN KEY (`instructor_detail_id`) REFERENCES `instructor_detail` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; DROP TABLE IF EXISTS `course`; CREATE TABLE `course` ( `id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(128) DEFAULT NULL, `instructor_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `TITLE_UNIQUE` (`title`), KEY `FK_INSTRUCTOR_idx` (`instructor_id`), CONSTRAINT `FK_INSTRUCTOR` FOREIGN KEY (`instructor_id`) REFERENCES `instructor` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1; DROP TABLE IF EXISTS `review`; CREATE TABLE `review` ( `id` int(11) NOT NULL AUTO_INCREMENT, `comment` varchar(256) DEFAULT NULL, `course_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `FK_COURSE_ID_idx` (`course_id`), CONSTRAINT `FK_COURSE` FOREIGN KEY (`course_id`) REFERENCES `course` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `id` int(11) NOT NULL AUTO_INCREMENT, `first_name` varchar(45) DEFAULT NULL, `last_name` varchar(45) DEFAULT NULL, `email` varchar(45) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; DROP TABLE IF EXISTS `course_student`; CREATE TABLE `course_student` ( `course_id` int(11) NOT NULL, `student_id` int(11) NOT NULL, PRIMARY KEY (`course_id`,`student_id`), KEY `FK_STUDENT_idx` (`student_id`), CONSTRAINT `FK_COURSE_05` FOREIGN KEY (`course_id`) REFERENCES `course` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT `FK_STUDENT` FOREIGN KEY (`student_id`) REFERENCES `student` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 2. Update hibernate.cfg.xml -------------------------------------- com.mysql.cj.jdbc.Driver jdbc:mysql://localhost:3306/hibernate_manytomany?useSSL=false&serverTimezone=UTC hibernate hibernate 3. Course.java -------------------------- package demo.entity; import java.util.ArrayList; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.Table; @Entity @Table(name = "course") public class Course { // define the fields, constructors, getters and setters, toString and add the annotation @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private int id; @Column(name = "title") private String title; // Many Courses can have One instructor @ManyToOne(cascade = {CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH}) @JoinColumn(name = "instructor_id") // create a column instructor_id in course table, add foreign key to it with id column of instructor Table private Instructor instructor; // ================================================================================= // Do this for OneToMany Uni-directional, One course can have many reviews @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinColumn(name = "course_id") // create a column course_id in Review table and add foreign key to it with references to id of course table private List reviews; public List getReviews() { return reviews; } public void setReviews(List reviews) { this.reviews = reviews; } // For Adding the reviews to the course public void addReview(Review theReview) { if(reviews == null) { reviews = new ArrayList(); } reviews.add(theReview); } // ================================================================================= @ManyToMany(fetch = FetchType.LAZY,cascade = {CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH}) @JoinTable( name = "course_student", joinColumns = @JoinColumn(name="course_id"), inverseJoinColumns = @JoinColumn(name="student_id") ) private List students; public List getStudents() { return students; } public void setStudents(List students) { this.students = students; } // For Adding the students to the course public void addStudent(Student theStudent) { if(students == null) { students = new ArrayList(); } students.add(theStudent); } // ================================================================================== public Course() { } public Course(String title) { this.title = title; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public Instructor getInstructor() { return instructor; } public void setInstructor(Instructor instructor) { this.instructor = instructor; } @Override public String toString() { return "Course [id=" + id + ", title=" + title + ", instructor=" + instructor + "]"; } } 4. Student.java ---------------------------- package demo.entity; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.Table; @Entity @Table(name="student") public class Student { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="id") private int id; @Column(name="first_name") private String firstName; @Column(name="last_name") private String lastName; @Column(name="email") private String email; // ================================================================================= @ManyToMany(fetch=FetchType.LAZY, cascade= {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH}) @JoinTable( name="course_student", joinColumns=@JoinColumn(name="student_id"), inverseJoinColumns=@JoinColumn(name="course_id") ) private List courses; public List getCourses() { return courses; } public void setCourses(List courses) { this.courses = courses; } // ================================================================================= public Student() { } public Student(String firstName, String lastName, String email) { this.firstName = firstName; this.lastName = lastName; this.email = email; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Override public String toString() { return "Student [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", email=" + email + "]"; } } 5. Delete the Uni and Bi-directional packages, create a package demo.application.manytomany 6. Create CreateCourseAndStudentsDemo.java ------------------------------------------------ package demo.application.manytomany; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Course; import demo.entity.Instructor; import demo.entity.InstructorDetail; import demo.entity.Review; import demo.entity.Student; public class CreateCourseAndStudentsDemo { public static void main(String[] args) { // create a factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Instructor.class).addAnnotatedClass(InstructorDetail.class).addAnnotatedClass(Course.class).addAnnotatedClass(Review.class).addAnnotatedClass(Student.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { // start a transaction Transaction tx = session.beginTransaction(); // Create a course Course course = new Course("Hibernate"); // save the course System.out.println("\nSaving the course"); session.save(course); System.out.println("\nSaved Course : "+course); // create the Students Student s1 = new Student("Debi", "prasad", "debi@prasad.com"); Student s2 = new Student("Vicky", "Debi", "Vicky@prasad.com"); Student s3 = new Student("Mishra", "prasad", "Mishra@prasad.com"); // add students to the course course.addStudent(s1); course.addStudent(s2); course.addStudent(s3); // save the students System.out.println("\nSaving the students"); session.save(s1); session.save(s2); session.save(s3); System.out.println("\nSaved Students : "+course.getStudents()); //commit transaction tx.commit(); System.out.println("Done"); }finally { // clean up the resources session.close(); factory.close(); } } } 7. Run the app and Test 8. Add courses for a student --------------------------------------- AddCoursesForDebi.java ------------------------------------ package demo.application.manytomany; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Course; import demo.entity.Instructor; import demo.entity.InstructorDetail; import demo.entity.Review; import demo.entity.Student; public class AddCoursesForDebi { // Debi was only in the Hibernate Course, now add courses public static void main(String[] args) { // create a factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Instructor.class).addAnnotatedClass(InstructorDetail.class).addAnnotatedClass(Course.class).addAnnotatedClass(Review.class).addAnnotatedClass(Student.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { // start a transaction Transaction tx = session.beginTransaction(); // get the student Debi from database int studentId = 1; Student theStudent = session.get(Student.class, studentId); System.out.println("Loaded Student : "+theStudent); System.out.println("Course for : "+theStudent.getFirstName()+" is : "+theStudent.getCourses()); // create more courses Course course1 = new Course("JAVA SE : Core Java"); Course course2 = new Course("Spring : Web Development"); // Add Debi to those courses course1.addStudent(theStudent); course2.addStudent(theStudent); // save the courses System.out.println("\nSaving the courses"); session.save(course1); session.save(course2); //commit transaction tx.commit(); System.out.println("Done"); }finally { // clean up the resources session.close(); factory.close(); } } } 9. Run and test the app 10. Get courses for a student ----------------------------------------- GetCoursesForDebi.java ------------------------ package demo.application.manytomany; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Course; import demo.entity.Instructor; import demo.entity.InstructorDetail; import demo.entity.Review; import demo.entity.Student; public class GetCoursesForDebi { // Debi was only in the Hibernate Course, now add courses public static void main(String[] args) { // create a factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Instructor.class).addAnnotatedClass(InstructorDetail.class).addAnnotatedClass(Course.class).addAnnotatedClass(Review.class).addAnnotatedClass(Student.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { // start a transaction Transaction tx = session.beginTransaction(); // get the student Debi from database int studentId = 1; Student theStudent = session.get(Student.class, studentId); System.out.println("Loaded Student : "+theStudent); System.out.println("Course for : "+theStudent.getFirstName()+" is : "+theStudent.getCourses()); //commit transaction tx.commit(); System.out.println("Done"); }finally { // clean up the resources session.close(); factory.close(); } } } 11. Run and test the app 12. Delete a course for a student --------------------------------------- package demo.application.manytomany; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Course; import demo.entity.Instructor; import demo.entity.InstructorDetail; import demo.entity.Review; import demo.entity.Student; public class DeleteCoursesForDebi { // Debi was only in the Hibernate Course, now add courses public static void main(String[] args) { // create a factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Instructor.class).addAnnotatedClass(InstructorDetail.class).addAnnotatedClass(Course.class).addAnnotatedClass(Review.class).addAnnotatedClass(Student.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { // start a transaction Transaction tx = session.beginTransaction(); // get the Hibernate course from database int courseId = 10; Course theCourse = session.get(Course.class, courseId); // delete the course System.out.println("Deleting Course : "+theCourse); session.delete(theCourse); //commit transaction tx.commit(); System.out.println("Done"); }finally { // clean up the resources session.close(); factory.close(); } } } 13. Run and test the app 14. Delete student from a course --------------------------------------- DeleteDebiStudentForCourse.java -------------------------------------- package demo.application.manytomany; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import demo.entity.Course; import demo.entity.Instructor; import demo.entity.InstructorDetail; import demo.entity.Review; import demo.entity.Student; public class DeleteDebiStudentForCourse { // Debi was only in the Hibernate Course, now add courses public static void main(String[] args) { // create a factory SessionFactory factory = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Instructor.class).addAnnotatedClass(InstructorDetail.class).addAnnotatedClass(Course.class).addAnnotatedClass(Review.class).addAnnotatedClass(Student.class).buildSessionFactory(); // create a session Session session = factory.getCurrentSession(); try { // start a transaction Transaction tx = session.beginTransaction(); // get the student Debi from database int studentId = 1; Student theStudent = session.get(Student.class, studentId); System.out.println("Loaded Student : "+theStudent); System.out.println("Course for : "+theStudent.getFirstName()+" is : "+theStudent.getCourses()); // delete student System.out.println("\nDeleting the student"); session.delete(theStudent); //commit transaction tx.commit(); System.out.println("Done"); }finally { // clean up the resources session.close(); factory.close(); } } } 15. Run and the app -------------------------------------------------------------------------------------------------------------------------------