配置hibernate.hbm.xml文件:
<hibernate-mapping package="com.zzh.dbTest">
<class name="Student" table="Student">
<id name="id" column="id">
<generator class="native">generator>
id>
<property name="name" type="java.lang.String">
<column name="name" not-null="false">column>
property>
<property name="age" type="java.lang.Integer">
<column name="age" not-null="false">column>
property>
<property name="createDate" type="java.util.Date">
<column name="createDate" not-null="false">column>
property>
class>
hibernate-mapping>
配置hibernate.cfg.xml文件:
注意,这个文件如果是默认的话,就是configuration中不写路径,需要将文件写在项目根目录。
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialectproperty>
<property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driverproperty>
<property name="hibernate.connection.url">property>
<property name="hibernate.connection.username">rootproperty>
<property name="hibernate.connection.password">yz1998property>
<property name="hibernate.show_sql">falseproperty>
<property name="hibernate.format_sql">falseproperty>
<property name="hibernate.current_session_context_class">threadproperty>
<mapping resource="com/zzh/dbTest/hibernate.hbm.xml"/>
session-factory>
hibernate-configuration>
TestDao中的代码:
package com.zzh.dbTest;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import java.util.Date;
public class TestDao {
public static void main(String[] args) {
Configuration configuration = new Configuration().configure();//这个配置文件如果不设置路径,默认找的是根目录下的hibernate.cfg.xml文件
//创建会话工厂
SessionFactory sessionFactory = configuration.buildSessionFactory();
//通过会话工厂创建会话
Session session =sessionFactory.openSession();
//进行增加,删改的时候必须使用事物进行提交
Transaction transaction =session.beginTransaction();
//添加一个学生
Student student = new Student();
student.setName("什么神奇");
student.setAge(20);
student.setCreateDate(new Date());
session.save(student);
transaction.commit();
}
}
1.创建Configuration,改对象用于读取hibernate.cfg.xml,并完成初始化
Configuration configuration= new Configuration().configure("hibernate.cfg.xml");//这里可以指定路径文件,也可以不用,默认找的就是hibernate.cfg.xml
2.创建SessionFactory会话工厂,是一个重量级的对象
SessionFactory sessionFactory = configuration.bulidSessionFactory();
3.创建Session相当于jdbc connection
Session session = sessionFactory.openSession();
4.使用事物提交
Transaction transaction = session.beginTransaction();//要求程序员在增删改的时候使用事物提交
5.保存
session.save(employee);//这个会被hibernate封装
6.事物提交
transaction.commit();
6.关闭资源
session.close();
hibernate处在的是持久层的位置,当session.save()的时候,就是把对象保存到数据库中。
将SessionFactory封装成单例
SessionFactory对象一旦通过Configuration对象创建,消耗资源是特别大的,为此,我们对一个数据库使用一个SessionFactory就够了。
下面来看代码
package com.zzh.dbutil;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class MySessionFactory{
//使用单例模式来建立sessionFactory
private static SessionFactory sessionFactory;
private MySessionFactory(){
}
static{
sessionFactory =new Configuration().configure().buildSessionFactory();
}
public static SessionFactory getSessionFactory(){
return sessionFactory;
}
}
Student对象一定要序列化,我们在之前的代码中是没有序列化的,但是在这里修改或者删除某个记录的时候一定要序列化。
因为序列化之后,Student的对象就是唯一的了,正好对应某一条记录,不然很有可能出现多个对象对应一条记录的情况。准备来说,就是可以唯一的标识Student对象。
我们在Student
类中只需要加上public class Student implements Serializable
就好了。
修改某条记录
先是通过主键来获得该对象实例,运用了发射机制,直接上代码
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import java.util.Date;
import com.zzh.dbutil.MySessionFactory;
public class TestDao {
public static void main(String[] args) {
//1.创建会话,因为会话工厂是很耗费资源的,所以我们采用单例模式来对一个数据库使用一个sessionFactory就够了
Session session = MySessionFactory.getSessionFactory().openSession();
//使用会话建立事物对象
Transaction transaction = session.beginTransaction();
//通过主键属性获取该对象实例
Student student = (Student)session.load(com.zzh.dbTest.Student.class,1);
student.setName("什么神奇很帅");
transaction.commit();
}
}
需要注意的问题是,这里直接student.setName()
就可以了,hibernate将Pojo分成了4个不同的状态,后面会详细解释,当这个对象处于某个状态的时候,就会直接调用对应的代码。这里实际上已经做了Update操作了。
删除
删除也需要注意一个问题,在使用student.load()
方法时,要知道,这就是将某条记录给加载给student对象。所以删除某条记录,其实就是要删除这个对象就好了。
所以
使用Session对象删除这条记录
public class TestDao {
public static void main(String[] args) {
Session session = MySessionFactory.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();
//1.先获取学生的某条记录
Student student = (Student)session.load(com.zzh.dbTest.Student.class, 2);
//2.将这个记录删除
session.delete(student);
transaction.commit();
}
}
配置另外一个数据库
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialectproperty>
<property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driverproperty>
<property name="hibernate.connection.url">property>
只需要修改这上面的信息,这里面如何改都能在/project/etc/hibernate.properties文件中找到
hibernate自动创建表
这里需要注意mysql的版本号的问题,mysql5以上使用用如下方言,不然会很坑,所以,将方言改成如下形式
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialectproperty>
改变hibernate.cfg.xml里面的信息,添加
<property name="hibernate.hbm2ddl.auto">createproperty>
create
是无论什么情况下,都会创建过表,改成update的话,就会表示如果表存在且属性没有改变(表结构没啥改变),就不会再创建过表。
杂项:Configuration
是类,SessionFactory
是接口,Session
是接口,Transaction
是接口。(听说面试题会考?我特么的)
Transaction
对象的rollback()方法,将数据回到之前没有修改的时候,就是回滚。具体用法
public static void updateStudent2() {
//关于回滚机制模板
//说明:MySessionFactory是我写的封装会话工厂的类,详细看上面
Session session= MySessionFactory.getSessionFactory().openSession();
Transaction transaction =null;
try {
transaction = session.beginTransaction();
Student student = (Student)session.load(Student.class, 1);
student.setName("什么神奇真的是啊");
student.setAge(20);
int a = 3/0;//此处抛了异常
transaction.commit();
} catch (Exception e) {
if(transaction!=null){
//回滚
transaction.rollback();
}
throw new RuntimeException(e.getMessage());
}
finally{
if(session!=null&&session.isOpen()){
session.close();
}
}
}
session不关闭的后果:会导致jdbc连接不关闭,占用大量的数据库资源,导致内存被大量使用,所以,一定要关闭。
作用:
+ 1.加载hibernate.cfg.xml文件的配置信息
+ 2.负责管理hibernate的配置x信息
+ 3.加载hibernate.cfg.xml文件中的驱动,url,用户名,密码,连接池.
+ 4.管理*.hbm.xml文件
使用方法
Configuration configuration = new Configuration().configure(yourpath);
yourpath
中写的是hibernate.cfg.xml
配置文件所在的位置,如果不填写,默认就是在根目录下的hibernate.cfg.xml文件。当然,你也可以将这个文件改名字,并且放在另外一个包中。实验如下:
com.zzh.config
的包,并且将原来的hibernate.cfg.xml文件改名成zzhStudent.cfg.xml
文件名放入这个包中。如图: 还记得我们在com.zzh.dbutil
包中写的MySessionFactory
类吗?这里面是用单例来获得sessionFactory的。我们先看看代码。
package com.zzh.dbutil;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class MySessionFactory{
//使用单例模式来建立sessionFactory
private static SessionFactory sessionFactory;
private MySessionFactory(){
}
static{
sessionFactory =new Configuration().configure().buildSessionFactory();
}
public static SessionFactory getSessionFactory(){
return sessionFactory;
}
}
修改configure()配置路径。
package com.zzh.dbutil;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class MySessionFactory{
//使用单例模式来建立sessionFactory
private static SessionFactory sessionFactory;
private MySessionFactory(){
}
static{
sessionFactory =new Configuration().configure("com/zzh/config/zzhStudent.cfg.xml").buildSessionFactory();
}
public static SessionFactory getSessionFactory(){
return sessionFactory;
}
}
然后运行就Ok了。
sessionFactory =new Configuration().configure("com/zzh/config/zzhStudent.cfg.xml").buildSessionFactory()
不同点详细说明
)getCurrentSession需要对.cfg.xml文件进行配置,这里面不只是可以用thread
一种配置,详细看文档,这里的thread表示线程使用同一个session代码如下
"current_session_context_class">thread
)每次使用openSession获得的session都是不同的,而getCurrentSession是相同的,可以写一段代码来比较hashcode值:
package com.zzh.dbTest;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import java.util.Date;
import com.zzh.dbutil.MySessionFactory;
public class TestDao {
public static void main(String[] args) {
Session session = MySessionFactory.getSessionFactory().getCurrentSession();
Session session2 = MySessionFactory.getSessionFactory().getCurrentSession();
System.out.println(session.hashCode()+ " : " +session2.hashCode());
Session session3 = MySessionFactory.getSessionFactory().openSession();
Session session4 = MySessionFactory.getSessionFactory().openSession();
System.out.println(session3.hashCode()+" : "+session4.hashCode());
}
}
输出结果:
356691811 : 356691811
248495761 : 552416003
不难发现,每次openSession()的时候都分配了一个新的session.顾而hashcode不同,但是getCurrentSession使用的都是改线程内的session.是相同的session,所以hashcode值相同。
)事物提交不同,在使用查询的时候,如果是openSession获得的session是不用在使用事物提交的(是在查询的时候!!),但是如果是getCurrentSession的话,是一定要进行事物提交的,我们来看下面的代码。
public class TestDao {
public static void main(String[] args) {
Session session = MySessionFactory.getSessionFactory().openSession();
Student student = (Student)session.load(Student.class, 1);
String name = student.getName();
System.out.println(name);
if(session!=null&&session.isOpen())
session.close();
}}
//通过opensession方法获得的session能不用事物提交来查询
//输出 什么神奇
再来看看使用getCurrentSession().
Session session = MySessionFactory.getSessionFactory().getCurrentSession();
Exception in thread "main" org.hibernate.HibernateException: Calling method 'load' is not valid without an active transaction (Current status: NOT_ACTIVE)
at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:346)
at com.sun.proxy.$Proxy33.load(Unknown Source)
at com.zzh.dbTest.TestDao.main(TestDao.java:13)
会抛出异常,我们在这里必须使用事物提交。代码如下:
public class TestDao {
public static void main(String[] args) {
Session session = MySessionFactory.getSessionFactory().getCurrentSession();
Transaction ts = session.beginTransaction();
Student student = (Student)session.load(Student.class, 1);
String name = student.getName();
ts.commit();
System.out.println(name);
if(session!=null&&session.isOpen())
session.close();
}}
运行成功,注意,ts.commit()得写到student.getName()的后面
)openSession获得的session是需要关闭的,否则大量占用资源,而getCurrentSession获得的session是不用手写关闭的,因为,它会自动关闭,但是我们一般就直接使用代码
if(session!=null&&session.isOpen())
session.close();
如果不加判断,使用getCurrentSession获得的session去关闭的话,会报错,因为,这里的session已经关闭了。