java8 之Lambda表达式在Hibernate的实战

前言

本文需要一定的java8特性基础,共涉及到了默认方法,方法引用,迭代集合(测试),函数式接口的设计。

另外,本文是对Hibernate的常见单表操作进行了练习,包含了增删改,模糊查询,部分字段查询,分页查询,多条件查询,分页+条件查询等。

项目下载:见博主的下载资源。hibernate增删改查和分页+java8

项目环境

项目是一个动态web项目,但是没有添加页面。使用了MVC架构,从dao层写到了service层。

中间过程设计了几个接口,用于支持service提交事务。

目录结构如图所示,其中test包主要是为了测试service中的方法。

hibernate.cfg.xml在src目录下。

org.feng.service.support包中设计了几个接口,用于支持service事务提交(原因在于,只使用Hibernate时,事务提交代码固定,因此设计函数式接口进行优化,去除冗余代码)。下图是src中的所有内容:

完整项目

数据表

数据库名是toursim_system,表名是place。

数据表中,id是主键,自增。

org.feng.util

package org.feng.util;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {
	private static SessionFactory sf;

	static {
		// 1 创建,调用空参构造
		Configuration conf = new Configuration().configure();

		// 2 根据配置信息,创建 SessionFactory对象
		sf = conf.buildSessionFactory();
	}

	/**
	 * 获取当前Session
	 * @return
	 */
	public static Session currentSession(){
		// 3 获得session
		return sf.getCurrentSession();
	}
}

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>
	<session-factory>
	
		<!-- 
		#hibernate.dialect org.hibernate.dialect.MySQLDialect
		#hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect
		#hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect
		#hibernate.connection.driver_class com.mysql.jdbc.Driver
		#hibernate.connection.url jdbc:mysql:///test
		#hibernate.connection.username gavin
		#hibernate.connection.password
		 -->
		 <!-- 数据库驱动 -->
		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
		 <!-- 数据库url -->
		<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/tourism_system</property>
		 <!-- 数据库连接用户名 -->
		<property name="hibernate.connection.username">root</property>
		 <!-- 数据库连接密码 -->
		<property name="hibernate.connection.password">root</property>
		<!-- 数据库方言
			不同的数据库中,sql语法略有区别. 指定方言可以让hibernate框架在生成sql语句时.针对数据库的方言生成.
			sql99标准: DDL 定义语言  库表的增删改查
					  DCL 控制语言  事务 权限
					  DML 操纵语言  增删改查
			注意: MYSQL在选择方言时,请选择最短的方言.
		 -->
		<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
		
		
		<!-- #hibernate.show_sql true 
			 #hibernate.format_sql true
		-->
		<!-- 将hibernate生成的sql语句打印到控制台 -->
		<property name="hibernate.show_sql">true</property>
		<!-- 将hibernate生成的sql语句格式化(语法缩进) -->
		<property name="hibernate.format_sql">true</property>
		<!-- 
		## auto schema export  自动导出表结构. 自动建表
		#hibernate.hbm2ddl.auto create		自动建表.每次框架运行都会创建新的表.以前表将会被覆盖,表数据会丢失.(开发环境中测试使用)
		#hibernate.hbm2ddl.auto create-drop 自动建表.每次框架运行结束都会将所有表删除.(开发环境中测试使用)
		#hibernate.hbm2ddl.auto update(推荐使用) 自动生成表.如果已经存在不会再生成.如果表有变动.自动更新表(不会删除任何数据).
		#hibernate.hbm2ddl.auto validate	校验.不自动生成表.每次启动会校验数据库中表是否正确.校验失败.
		 -->
		<property name="hibernate.hbm2ddl.auto">update</property>
		<property name="current_session_context_class">thread</property>

		<mapping class="org.feng.entity.Place"/>

	</session-factory>
</hibernate-configuration>

org.feng.entity

实体类中使用注解与表映射:表名映射,id自增,其他各列映射。

package org.feng.entity;

import java.io.Serializable;

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="place")
public class Place implements Serializable {
	
	/**
	 * Feng2019年10月11日
	 */
	private static final long serialVersionUID = -5980494330051306592L;
	
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private Integer id;
	@Column(name="name")
	private String name;
	@Column(name="cost")
	private Integer cost;
	@Column(name="city")
	private String city;
	@Column(name="description")
	private String description;
	@Column(name="picture")
	private String picture;
	
	public Place() {

	}
	
	public Place(Integer id) {
		this.id = id;
	}
	
	// 该构造器用于查询语句HQL的实现
	public Place(String name, Integer cost, String description) {
		this(null, name, cost, null, description, null);
	}

	public Place(Integer id, String name, Integer cost, String city, String description, String picture) {
		this.id = id;
		this.name = name;
		this.cost = cost;
		this.city = city;
		this.description = description;
		this.picture = picture;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getCost() {
		return cost;
	}

	public void setCost(Integer cost) {
		this.cost = cost;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public String getPicture() {
		return picture;
	}

	public void setPicture(String picture) {
		this.picture = picture;
	}

	@Override
	public String toString() {
		return "Place [id=" + id + ", name=" + name + ", cost=" + cost + ", city=" + city + ", description="
				+ description + ", picture=" + picture + "]";
	}
	
	
}

 

org.feng.dao

package org.feng.dao;

import java.util.List;
import java.util.Map;

import org.feng.entity.Place;
/**
 * 景点信息操作:数据访问接口
 * @author Feng
 * 2019年10月11日下午2:40:11
 */
public interface PlaceDao {

	/**
	 * 分页
	 * @param pageNo
	 * @param pageSize
	 * @return
	 */
	public List<Place> getByPage(int pageNo, int pageSize);
	
	/**
	 * 分页+条件查询
	 * @param pageNo
	 * @param pageSize
	 * @param place
	 * @return
	 */
	public List<Place> getByPage(int pageNo, int pageSize, Place place);
	
	/**
	 * 获取前n条数据
	 * @param n
	 * @return
	 */
	public List<Place> getTopN(int n);
	
	
	/**
	 * 获取表中的部分数据:name列、cost列、description列
	 * @return
	 */
	public List<Place> getSubInfo();
	
	/**
	 * 查询表,通过Hibernate封装为List
	 * @return
	 */
	public List<Map<String, Object>> getMapList();
	
	/**
	 * 通过id查询到Place信息
	 * @param id
	 * @return
	 */
	public Place getById(String id);
	
	
	
	/**
	 * 通过景点名查找某一景点
	 * @param place
	 * @return
	 */
	public Place getByName(Place place);
	
	/**
	 * 结果集
	 * @param place
	 * @return
	 */
	public List<Place> placeList();
	
	/**
	 * 返回通过景点名查询的结果
	 * @param name
	 * @return
	 */
	public List<Place> getPlaceByNameLike(String name);
	
	/**
	 * 返回通过城市名查询的结果
	 * @param city
	 * @return
	 */
	public List<Place> getPlaceByCityLike(String city);
	
	
	/**
	 * 获取所有景点名
	 * @return
	 */
	public List<String> getPlaceName();
	
	

	/**
	 * 插入数据
	 * @param type 任意一个实体类
	 * @return 
	 */
	void insert(Place type);
	
	
	/**
	 * 修改数据
	 * @param type 任意一个实体类
	 */
	void update(Place type);
	
	
	/**
	 * 删除方法:通过id删除
	 * 如果id为int值,拼空字符串;
	 * 当int id =  1; -> 1+""
	 * @param id
	 * @return 数据库中影响的行数
	 */
	void delete(String id);
}

 

org.feng.dao.impl

继承了HibernateUtil工具类获取session,实现了PlaceDao接口,实现其中的抽象方法。

package org.feng.dao.impl;

import java.util.List;
import java.util.Map;

import org.feng.dao.PlaceDao;
import org.feng.entity.Place;
import org.feng.util.HibernateUtil;

public class PlaceDaoImpl extends HibernateUtil implements PlaceDao {

	
	@SuppressWarnings("unchecked")
	@Override
	public List<Place> placeList(){
		return currentSession()
				.createQuery("from Place")
				.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Place> getPlaceByNameLike(String name) {
		return currentSession()
				.createQuery("from Place where name like ?")
				.setString(0, "%"+name+"%")
				.list();
	}


	@SuppressWarnings("unchecked")
	@Override
	public List<Place> getPlaceByCityLike(String city) {
		return currentSession()
				.createQuery("from Place where city like ?")
				.setString(0, "%"+city+"%")
				.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<String> getPlaceName() {
		return currentSession()
				.createQuery("select name from Place")
				.list();
	}

	@Override
	public void insert(Place type) {
		currentSession().save(type);
	}

	@Override
	public void update(Place type) {
		currentSession().update(type);
	}

	@Override
	public void delete(String id) {
		currentSession().delete(new Place(Integer.valueOf(id)));
	}

	@Override
	public Place getById(String id) {
		return (Place) currentSession()
			.createQuery("from Place where id = ?")
			.setInteger(0, Integer.valueOf(id))
			.uniqueResult();
	}

	@Override
	public Place getByName(Place place) {
		return (Place) currentSession()
				.createQuery("from Place place where place.name = :name")
				.setString("name", place.getName())
				.uniqueResult();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Place> getSubInfo() {
		return currentSession()
				.createQuery("select new Place(name, cost, description) from Place")
				.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Map<String, Object>> getMapList() {
		return currentSession()
				.createQuery("select new Map(name as placeNmae,description as info) from Place")
				.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Place> getByPage(int pageNo, int pageSize) {
		return currentSession()
				.createQuery("from Place")
				.setFirstResult((pageNo - 1) * pageSize)
				.setMaxResults(pageSize)
				.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Place> getTopN(int n) {
		return currentSession()
				.createQuery("from Place")
				.setMaxResults(n)
				.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Place> getByPage(int pageNo, int pageSize, Place place) {
		return currentSession()
				.createQuery("from Place place where place.name like ?")
				.setFirstResult((pageNo - 1) * pageSize)
				.setMaxResults(pageSize)
				.setString(0, "%"+place.getName()+"%")
				.list();
	}
}

org.feng.service

service层的方法与Dao层的方法一致。

特殊在于,这里的service接口继承了ServiceSupport接口,该接口中写了3个默认的方法,用于查询、修改、增加、删除、条件查询。

package org.feng.service;

import java.util.List;
import java.util.Map;

import org.feng.entity.Place;
import org.feng.service.support.ServiceSupport;

public interface PlaceService extends ServiceSupport{

	
	/**
	 * 获取表中的部分数据:name列、cost列、description列
	 * @return
	 */
	public List<Place> getSubInfo();
	
	/**
	 * 结果集
	 * @param place
	 * @return
	 */
	public List<Place> placeList();
	
	/**
	 * 返回通过景点名查询的结果
	 * @param name
	 * @return
	 */
	public List<Place> getPlaceByNameLike(String name);
	
	/**
	 * 返回通过城市名查询的结果
	 * @param city
	 * @return
	 */
	public  List<Place> getPlaceByCityLike(String city);
	
	public Place getByName(Place place);
	
	/**
	 * 查找部分信息,放到Map中
	 * @return
	 */
	public List<Map<String, Object>> getMapList();
	
	/**
	 * 获取所有景点名
	 * @return
	 */
	public List<String> getPlaceName();
	
	public Place getById(String id);
	
	void insert(Place type);
	
	void update(Place type);
	
	void delete(String id);
	
	public List<Place> getByPage(int pageNo, int pageSize);
	
	public List<Place> getByPage(int pageNo, int pageSize, Place place);
	
	public List<Place> getTopN(int n);
}

org.feng.service.support

自定义函数式接口。

package org.feng.service.support;

import org.feng.util.HibernateUtil;
import org.hibernate.Transaction;

/**
 * 查询支持接口:提供默认的事务操作处理。返回值为java.util.List等
 * @author Feng
 * 2019年10月10日下午4:41:02
 */
@FunctionalInterface
public interface QuerySupport<T> {
	
	/**
	 * 查询专用:当查询无参数注入时(查询所有,无条件);
	 * 当查询有参数注入(有条件查询),也不影响,参数直接从service层进入dao层的方法。
	 * @param <T> 某一类型,可以是entity类型、String、List等
	 * @return
	 */
	default T doQuery() {
		Transaction tx = null;
		T result = null;
		try {
			tx = HibernateUtil.currentSession().beginTransaction();
			result = execute();
			tx.commit();
		} catch (Exception e) {
			if(tx != null) {
				tx.rollback();
			}
		}
		return result;
	}
	
	
	

	/**
	 * 查询操作
	 * @param <T>
	 * @return
	 */
	T execute();
}
package org.feng.service.support;


import org.feng.util.HibernateUtil;
import org.hibernate.Transaction;
/**
 * 插入、修改删除操作的接口
 * @author Feng
 * 2019年10月10日下午4:44:24
 */
@FunctionalInterface
public interface SaveOrUpdateOrDeleteSupport {

	/**
	 * 封装:事务提交和回滚,主要是用于增加、删除、修改操作;
	 */
	default void doSomeThing() {
		Transaction tx = null;
		try {
			tx = HibernateUtil.currentSession().beginTransaction();
			execute();
			tx.commit();
		} catch (Exception e) {
			if(tx != null) {
				tx.rollback();
			}
		}
	}
	
	
	/**
	 * 插入、修改、删除
	 */
	void execute();
}
package org.feng.service.support;

import org.feng.util.HibernateUtil;
import org.hibernate.Transaction;
/**
 * 复杂查询,有条件查询
 * @author Feng
 * 2019年10月11日下午2:21:36
 * @param <T> 条件(sql的参数)
 * @param <R> 结果
 */
@FunctionalInterface
public interface ComplexQuerySupport<T, R> {

	R complexQuery(T t);
	
	
	default R doQuery(T t) {
		Transaction tx = null;
		R result = null;
		try {
			tx = HibernateUtil.currentSession().beginTransaction();
			result = complexQuery(t);
			tx.commit();
		} catch (Exception e) {
			if(tx != null) {
				tx.rollback();
			}
		}
		return result;
	}
	
}
package org.feng.service.support;

public interface ServiceSupport {

	/**
	 * 面向接口:查询
	 * @param <T>
	 * @param support
	 * @return
	 */
	default <T> T doQuery(QuerySupport<T> support){
		return support.doQuery();
	}
	
	/**
	 * 面向接口操作:增加、删除、修改
	 * @param support
	 */
	default void doSomeThing(SaveOrUpdateOrDeleteSupport support) {
		support.doSomeThing();
	}
	
	/**
	 * 复杂查询:有条件查询
	 * @param support
	 * @param argument
	 * @return
	 */
	default <R, T> R doComplexQuery(ComplexQuerySupport<T, R> support, T argument) {
		return support.doQuery(argument);
	}
}

org.feng.service.impl

service实现类,其中可以调用PlaceService接口继承得来的3个默认方法,分别用于查询、增加、修改、删除等的事务提交操作。也就是说,在本层中不需要显示写出事务提交部分的代码,因为这些操作已经在对应的***Support.java接口文件中做过了。

package org.feng.service.impl;

import java.util.List;
import java.util.Map;

import org.feng.dao.PlaceDao;
import org.feng.dao.impl.PlaceDaoImpl;
import org.feng.entity.Place;
import org.feng.service.PlaceService;

public class PlaceServiceImpl implements PlaceService {

	private PlaceDao dao;
	
	public PlaceServiceImpl() {
		dao = new PlaceDaoImpl();
	}
	
	
	/**
	 * 使用java8的方法引用:dao::placeList
	 * 意思是,dao调用placeList的方法,并返回。
	 */
	@Override
	public List<Place> placeList() {
		return doQuery(dao::placeList);
	}


	@Override
	public List<Place> getPlaceByNameLike(String name) {
		return doComplexQuery(dao::getPlaceByNameLike, name);
	}

	@Override
	public List<Place> getPlaceByCityLike(String city) {
		return doComplexQuery(dao::getPlaceByCityLike, city);
	}

	@Override
	public List<String> getPlaceName() {
		return dao.getPlaceName();
	}

	@Override
	public void insert(Place type) {
		doSomeThing(() -> dao.insert(type));
	}
	
	@Override
	public void update(Place type) {
		doSomeThing(() -> dao.update(type));
	}

	@Override
	public void delete(String id) {
		doSomeThing(() -> dao.delete(id));
	}


	@Override
	public Place getById(String id) {
		return doComplexQuery(dao::getById, id);
	}


	@Override
	public Place getByName(Place place) {
		return doComplexQuery(dao::getByName, place);
	}


	@Override
	public List<Place> getSubInfo() {
		return doQuery(dao::getSubInfo);
	}


	@Override
	public List<Map<String, Object>> getMapList() {
		return doQuery(dao::getMapList);
	}


	@Override
	public List<Place> getByPage(int pageNo, int pageSize) {
		return doQuery(()->{
			return dao.getByPage(pageNo, pageSize);
		});
	}


	@Override
	public List<Place> getTopN(int n) {
		return doComplexQuery(dao::getTopN, n);
	}


	@Override
	public List<Place> getByPage(int pageNo, int pageSize, Place place) {
		return doQuery(()->{
			return dao.getByPage(pageNo, pageSize, place);
		});
	}
}

org.feng.service.impl.test

测试使用了junit测试。

经过测试,目标方法均可正常执行。

package org.feng.service.impl.test;

import org.feng.entity.Place;
import org.feng.service.PlaceService;
import org.feng.service.impl.PlaceServiceImpl;

import org.junit.Test;

public class ServiceTest {

	PlaceService service = new PlaceServiceImpl();
	
	@Test
	public void insert() {
		service.insert(new Place(0, "西湖", 0, "杭州", "水很好", ""));
	}
	
	@Test
	public void update() {
		service.update(new Place(20, "西湖", 0, "杭州", "水很好", "beau.png"));
	}
	
	
	@Test
	public void query() throws Exception {
		service.placeList().forEach(System.out::println);
	}
	
	@Test
	public void testLike() {
		service.getPlaceByNameLike("大").forEach(System.out::println);
	}
	
	@Test
	public void testId() {
		System.out.println(service.getById("1"));
	}
	
	@Test
	public void testPlaceByName() {
		Place place = new Place();
		place.setName("大雁塔");
		
		System.out.println(service.getByName(place));
	}
	
	@Test
	public void testSubInfo() {
		service.getSubInfo().forEach(System.out::println);
	}
	
	@Test
	public void testMap() {
		service.getMapList().forEach(System.out::println);
	}
	
	@Test
	public void page() {
		System.out.println("第1页:");
		service.getByPage(1, 2).forEach(System.out::println);
		System.out.println("第2页:");
		service.getByPage(2, 2).forEach(System.out::println);
	}
	
	@Test
	public void complexPage() {
		System.out.println("第1页:");
		Place place = new Place();
		place.setName("大");
		service.getByPage(1, 1, place).forEach(System.out::println);
		
		System.out.println("第2页:");
		service.getByPage(2, 1, place).forEach(System.out::println);
	}
}

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你家宝宝

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

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值