Java:Hibernate框架的项目配置及应用

简介

Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。
最具革命意义的是,Hibernate可以在应用EJB的JaveEE架构中取代CMP,完成数据持久化的重任。

即:全自动非常方便,数据持久化,但由于是全自动,如果想要自定义功能会非常麻烦。

配置

1.jar包
这些这些是必须要导入的 jar 包,其他的可以在官网下载的文件里面自行选择。
下面是我整个项目的 jar 包

2.配置文件
hibernate.cfg.xml 文件(不完整,可添加)

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
	<!--hibernate.可以省略,hibernate会做判断,如 hibernate.c3p0.max_size可写成c3p0.max_size -->
	<session-factory>
		<property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
		<property name="connection.url">jdbc:mysql:///study?serverTimezone=GMT%2B8</property>
		<property name="connection.username">root</property>
		<property name="connection.password">123456</property>

		<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
		<!-- 指定连接池里最大连接数 -->
		<property name="hibernate.c3p0.max_size">20</property>
		<!-- 指定连接池里最小连接数 -->
		<property name="hibernate.c3p0.min_size">1</property>
		<!-- 指定连接池里连接的超时时长 -->
		<property name="hibernate.c3p0.timeout">5000</property>
		<!-- 指定连接池里最大缓存多少个Statement对象 -->
		<property name="hibernate.c3p0.max_statements">100</property>
		<property name="hibernate.c3p0.idle_test_period">3000</property>
		<property name="hibernate.c3p0.acquire_increment">2</property>
		<property name="hibernate.c3p0.validate">true</property>

		<!--指定数据库名,mysql低版本曾用hibernate.default_schema表示数据库名 -->
		<property name="hibernate.default_catalog">study</property>

		<!-- 指定数据库方言 -->
		<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
		
		<!-- 显示Hibernate持久化操作所生成的SQL -->
		<property name="show_sql">true</property>

		<!-- 将SQL脚本进行格式化后再输出 -->
		<property name="hibernate.format_sql">true</property>

		<!-- 测试环境使用create/create-drop 正式环境使用update/validate -->
		<property name="hbm2ddl.auto">update</property>

		<!--扫描实体包 -->
		<mapping class="com.abc.entity.Student" />
		<mapping class="com.abc.entity.Customer" />
		<mapping class="com.abc.entity.Order" />
	</session-factory>
</hibernate-configuration>

log4j.properties 日志信息输送文件

### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### direct messages to file hibernate.log ###
#log4j.appender.file=org.apache.log4j.FileAppender
#log4j.appender.file.File=D:\\log\\hibernate.log
#log4j.appender.file.layout=org.apache.log4j.PatternLayout
#log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### set log levels - for more verbose logging change 'info' to 'debug' ###

# DEBUG,INFO,WARN,ERROR,FATAL
log4j.rootLogger=ERROR, stdout

现在是控制台打印日志信息,注释掉的是输出日志信息到文件。
3.工具类
HibernateUtil 类

public class HibernateUtil {
	private static final SessionFactory SESSION_FACTORY;
	static {
		try {
			SESSION_FACTORY = new Configuration().configure().buildSessionFactory();
		} catch (Throwable ex) {
			ex.printStackTrace();
			throw new ExceptionInInitializerError(ex);
		}
	}
	public static Session getSession() {
		return SESSION_FACTORY == null ? null : SESSION_FACTORY.openSession();
	}
	public static void close(Session ses) {
		if (ses != null) {
			ses.close();
		}
	}
}

HibernateTemplate 类

public class HibernateTemplate {
	public static final Object execute(HibernateCallback hc) {
		Session ses = null;
		Transaction tx = null;
		Object obj = null;
		try {
			ses = HibernateUtil.getSession();
			tx = ses.beginTransaction();
			obj = hc.doHibernate(ses);
			tx.commit();
		} catch (HibernateException e) {
			if (tx != null) {
				tx.rollback();
			}
			e.printStackTrace();
		} finally {
			HibernateUtil.close(ses);
		}
		return obj;
	}
}

HibernateCallback 类

public interface HibernateCallback {
	Object doHibernate(Session ses) throws HibernateException;
}

应用注解将实体类与数据表建立映射关系

1.一张独立的表 student:id,name,birthday,gender(0,1)

Student 实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
//表示当前类是一个实体类
@Entity
//表示该实体类对应一张表
@Table(name = "student")
//动态更新和添加
@DynamicUpdate
@DynamicInsert
public class Student {
	//主键
	@Id
	//主键生成策略
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;
	//列设置,非空唯一
	@Column(unique = true, nullable = false)
	private String name;
	@Column
	private LocalDate birthday;
	@Column
	@Enumerated(EnumType.ORDINAL)
	private Gender gender;
}

Gender 是枚举

public enum Gender {
	MALE, FEMALE;
}

2.如果表有关联关系,可以实现关联
比如:顾客和订单是一对多的关系
顾客表customer:id,name
订单表order:id,orderno,price,customer_id

Customer 实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "customer")
public class Customer {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;
	private String name;
	// 一对多
	// 配置级联  cascade
	// 加载模式  fetch
	@OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	private List<Order> orders;
}

Order 实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "order")
public class Order {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;
	private String orderNo;
	private Double price;
	// 多对一
	@ManyToOne
	// 外键
	@JoinColumn(name = "customer_id", referencedColumnName = "id")
	private Customer customer;

	@Override
	public String toString() {
		return "Order [id=" + id + ", orderNo=" + orderNo + ", price=" + price + "]";
	}
}

关于Hibernate框架

HQL—— Hibernate Query Language

 * 它是Hibernate框架提供的一种半面向对象,半面向关系的查询语句,所以性能较高
 * hql中出现的都是类名以及属性名,但是它本质上还是一种SQL语句.
 * 
 * 补充:
 * Hibernate官方其实提供了三种不同的方式进行查询:
 * 1.原生SQL			直接使用原生SQL来进行查询
 * 2.HQL			半面向对象,半面向关系的查询语句(推荐)
 * 3.QBC			纯面向对象,完全不用写HQL和SQL,性能低于SQL和HQL方式

Hibernate在级联查询时,会根据级联情况自动提供加载模式:
* 一对一:默认采用迫切加载
* 一对多:默认多的一方采用懒加载
* 多对一:默认一的一方采用迫切加载
* 多对多:默认采用懒加载

用Hibernate框架操作数据库(增删改查)

注意:以下代码全部采用 lambda 表达式(匿名内部类重写方法)

当操作代码运行时,如果表存在,就直接操作;
如果表不存在,会先根据映射关系建表,再进行操作。

但是,它在建表时,非主键列并不是按照顺序排列,所以,自动创建的表可能不太理想。
如果可以的话,就手动建表。当然,如果对这无所谓,那就随心所欲、为所欲为吧。

1.对一张表进行操作

StudentDao 接口

public interface StudentDao {
	/**
	 * 添加学生
	 */
	long insertStudent(Student student);
	/**
	 * 批量添加多个学生
	 */
	void insertBatchStudents(List<Student> students);
	/**
	 * 删除学生
	 */
	void deleteStudentById(Student student);
	/**
	 * 根据姓名删除学生(模糊)
	 */
	int deleteStudentsByName(String name);
	/**
	 * 修改学生
	 */
	void updateStudent(Student student);
	/**
	 * 查询学生
	 */
	Student selectStudentById(Long id);
	List<Student> selectAllStudents();
	List<Student> selectStudentsByName(String name);
}

StudentDaoImpl 实现类

public class StudentDaoImpl implements StudentDao {
	@Override
	public long insertStudent(Student student) {
		return (long) HibernateTemplate.execute(ses -> ses.save(student));
	}
	@Override
	public void insertBatchStudents(List<Student> students) {
		HibernateTemplate.execute(ses -> {
			for (Student student : students) {
				ses.save(student);
			}
			return null;
		});
	}
	@Override
	public void deleteStudentById(Student student) {
		HibernateTemplate.execute(ses -> {
			ses.delete(student);
			return null;
		});
	}
	@Override
	public int deleteStudentsByName(String name) {
		return (int) HibernateTemplate.execute(ses -> ses.createQuery("delete from Student where name like :name")
				.setParameter("name", "%" + name + "%").executeUpdate());
	}
	@Override
	public void updateStudent(Student student) {
		HibernateTemplate.execute(ses -> {
			ses.update(student);
			return null;
		});
	}
	@Override
	public Student selectStudentById(Long id) {
		return (Student) HibernateTemplate.execute(ses -> ses.get(Student.class, id));
	}
	@SuppressWarnings("unchecked")
	@Override
	public List<Student> selectAllStudents() {
		return (List<Student>) HibernateTemplate.execute(ses -> ses.createQuery("from Student").list());
	}
	@SuppressWarnings("unchecked")
	@Override
	public List<Student> selectStudentsByName(String name) {
		return (List<Student>) HibernateTemplate.execute(ses -> ses.createQuery("from Student where name like :name")
				.setParameter("name", "%" + name + "%").list());
	}
}

其中,createQuery() 方法的参数语句就是上面提到的 HQL 语句,里面需要设置的参数用 “:名字”,后面跟设置参数方法 setParameter(“名字”,变量) 。最后一个结果用 uniqueResult() ,多个结果用 list() 。

从上面代码可以看出,每个方法的代码都差不多,并且代码量很少,这都源于 Hibernate 框架的强大功能。

2.对互相关联的表进行级联操作

CustomerDao 接口

public interface CustomerDao {
	/**
	 * 级联插入数据
	 * 添加顾客的同时,如果顾客有订单信息,则级联添加订单信息
	 */
	void insertCustomerAndOrders(Customer customer);
	/**
	 * 级联查询方法[懒加载,迫切加载]
	 * 查询顾客信息,如果该顾客有订单信息,则级联查询订单信息
	 */
	Customer selectCustomerAndOrdersById(Long id);
}

CustomerDaoImpl 实现类

public class CustomerDaoImpl implements CustomerDao {
	@Override
	public void insertCustomerAndOrders(Customer customer) {
		HibernateTemplate.execute(ses -> ses.save(customer));
	}
	@Override
	public Customer selectCustomerAndOrdersById(Long id) {
		return (Customer) HibernateTemplate.execute(
				ses -> ses.createQuery("select c from Customer c join Order o on c.id=o.customer.id where c.id=:id")
						.setParameter("id", id).uniqueResult());
	}
}

其中,select 语句比 from 语句提供了更多的对结果集的控制。
级联插入只用了一行代码,只要映射关系写好了,Hibernate 会自动把数据进行级联插入。而级联查询根据其 HQL 语句可分为 显式关联隐式关联

比如:
OrderDao 接口

public interface OrderDao {
	/**
	 * 根据顾客名字查询其订单
	 */
	List<Order> selectOrdersByCustomerName(String name);
}

OrderDaoImpl 实现类

public class OrderDaoImpl implements OrderDao {
	@SuppressWarnings("unchecked")
	@Override
	public List<Order> selectOrdersByCustomerName(String name) {
		// 显式关联
		return (List<Order>) HibernateTemplate.execute(
				ses -> ses.createQuery("select o from Order o join Customer c on o.customer.id=c.id where c.name=:name")
						.setParameter("name", name).list());
		// 隐式关联
		return (List<Order>) HibernateTemplate.execute(
				ses -> ses.createQuery("from Order o where o.customer.name=:name").setParameter("name", name).list());
	}
}

总结

Hibernate 框架的功能还有很多,这里我只写了暂时用到的一部分,还有许多其他更加强大的功能需要慢慢摸索。

前路漫长,未来可期

  • 1
    点赞
  • 0
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:数字20 设计师:CSDN官方博客 返回首页
评论

打赏作者

toollong

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值