spring boot整合hibernate,druid 连接 postgresql

x33g5p2x  于2021-12-24 转载在 其他  
字(11.6k)|赞(0)|评价(0)|浏览(363)

参考文章:spring boot整合hibernate 连接 Oracle

概述--Hibernate与JPA

  JPA,Java Persistence Api,中文译名为:Java持久层Api。是一个基于ORM(或叫O/R mapping ,对象关系映射)的标准规范,在这个规范中,JPA只定义标准规则,不提供实现。目前,JPA的主要实现有Hibernate,EclipseLink,OpenJPA等。

  由于Hibernate在数据访问解决技术领域的霸主地位,所以JPA标准基本由Hibernate主导。

Pom依赖结构

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<!--阿里druid数据库链接依赖-->
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid-spring-boot-starter</artifactId>
  <version>1.1.9</version>
</dependency>

<!--事务管理--原子性,一致性,隔离性,持久性-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

<!--使用mysql时引入-->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
</dependency>

<!--使用postgresql时引入-->
<dependency>
  <groupId>org.postgresql</groupId>
  <artifactId>postgresql</artifactId>
</dependency>

application.yml配置

# postgresql 环境配置
server:
  port: 18005
  max-http-header-size: 8192
logging:
  level:
    root: info
spring:
  datasource:
    url: jdbc:postgresql://10.101.15.59:5432/postgres
    username: root
    password: 123abc
    driverClassName: org.postgresql.Driver
    platform: postgres
    type: com.alibaba.druid.pool.DruidDataSource
    # type: org.apache.commons.dbcp2.BasicDataSource
    initialization-mode: always

    # ============================== druid ============================== #
    druid:
      #最大活跃数
      maxActive: 20
      #初始化数量
      initialSize: 1
      #最大连接等待超时时间
      maxWait: 60000
      #打开PSCache,并且指定每个连接PSCache的大小
      poolPreparedStatements: true
      maxPoolPreparedStatementPerConnectionSize: 20
      #通过connectionProperties属性来打开mergeSql功能;慢SQL记录
      #connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
      minIdle: 1
      timeBetweenEvictionRunsMillis: 60000
      minEvictableIdleTimeMillis: 300000
      validationQuery: select 1 from dual
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      #配置监控统计拦截的filters,去掉后监控界面sql将无法统计,'wall'用于防火墙
      filters: stat, wall, log4j

  # ============================= spring jpa 配置 ============================= #
  jpa:
    show_sql: true
    database-platform: org.hibernate.dialect.PostgreSQL9Dialect
    # database-platform: cn.luutqf.springboot.dialect.JsonbPostgresDialect
    hibernate:
      ddl-auto: update  # none: 关闭hibernate的自动创建表结构的机制
    properties:
      hibernate:
        dialect: org.hibernate.dialect.PostgreSQLDialect
        hbm2ddl.auto: update
        jdbc.lob.non_contextual_creation: true
        format_sql: true
        temp:
          # 兼容SpringBoot2.X, 关闭 Hibernate尝试验证PostgreSQL的CLOB特性
          use_jdbc_metadata_defaults: false

工程目录结构

DataSource配置文件

package org.fiend.config;

import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;

/**
 * postgresql data source config
 * @author fiend 2018/12/5
 */
@Configuration
public class DataSourceConfig {
    // @Primary
    @Bean(name="dataSource")
    @ConfigurationProperties(prefix="spring.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder.create().type(dataSourceType).build();
    }

    @Value("${spring.datasource.type}")
    private Class<? extends DataSource> dataSourceType;

    /**
     * 配置监控服务器
     * @return 返回监控注册的servlet对象
     */
    @Bean
    @SuppressWarnings("unchecked")
    public ServletRegistrationBean statViewServlet() {
        ServletRegistrationBean servletRegistrationBean =
                new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
        // 添加IP白名单
        servletRegistrationBean.addInitParameter("allow", "192.168.25.125,127.0.0.1");
        // 添加IP黑名单,当白名单和黑名单重复时,黑名单优先级更高
        servletRegistrationBean.addInitParameter("deny", "192.168.25.123");
        // 添加控制台管理用户
        servletRegistrationBean.addInitParameter("loginUsername", "druid");
        servletRegistrationBean.addInitParameter("loginPassword", "123456");
        // 是否能够重置数据
        servletRegistrationBean.addInitParameter("resetEnable", "false");
        return servletRegistrationBean;
    }

    /**
     * 配置服务过滤器
     * @return 返回过滤器配置对象
     */
    @Bean
    @SuppressWarnings("unchecked")
    public FilterRegistrationBean statFilter() {
        FilterRegistrationBean filterRegistrationBean=new FilterRegistrationBean(new WebStatFilter());
        // 添加过滤规则
        filterRegistrationBean.addUrlPatterns("/*");
        // 忽略过滤格式
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*,");
        return filterRegistrationBean;
    }
}

Entity文件

package org.fiend.entity;

import javax.persistence.*;
import java.io.Serializable;

/**
 * @author fiend 2018/12/5
 */
@Entity
@Table(catalog="public", name="user")
public class User implements Serializable {  //序列化在Jpa需要
    // @Id是用来标识主键的,而@GeneratedValue则是用来指定主键策略的
    @Id
    @GeneratedValue
    private String name;

    // @Column(name = "count", nullable = false)
    private Integer count;

    public String getName() {
        return name;
    }

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

    public Integer getCount() {
        return count;
    }

    public void setCount(Integer count) {
        this.count = count;
    }
}

Repository文件

package org.fiend.repository;

import org.fiend.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import javax.transaction.Transactional;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * @author langpf 2018/12/10
 */
@Repository
public interface UserRepository extends JpaRepository<User, String> {
    /**
     * 进行数据库操作, 可以通过自定义HQL来完成符合个性的其他操作
     * 通过@Query注解, 完成了HQL的书写, 其中“:name”与下方的@Param注解中参数保持一致。
     * HQL可使用Hibernate的SQL生成和缓存策略
     * HQL中一些关键字如 SELECT, FROM 和 WHERE等, 是不区分大小写的, 但是一些属性如表名和列名区分大小写
     */
    @Query(value = "SELECT u FROM User u WHERE name=:name")
    User findName(@Param("name") String name);

    /**
     * 使用SQL语句, nativeQuery为true代表使用SQL语言
     * 建议尽可能的使用HQL语句, 以避免数据库关于可移植性的麻烦,  且HQL可使用Hibernate的SQL生成和缓存策略。
     */
    @Query(value = "insert into User value(?,?,?)", nativeQuery = true)
    @Transactional
    @Modifying
    int countUserBy(@Param("id") Integer id, @Param("name") String name, 
                    @Param("password") String password);

    /**
     * 根据用户名查询
     */
    @Query("select t from User t where t.name = :name")
    User findByUserName(@Param("name") String name);

    /**
     * 查询全部
     */
    @Query("select t from User t")
    List<User> find();

    /**
     * 删除, 必须加入@Modifying和@Transactional
     */
    @Modifying
    @Transactional
    @Query("delete from User u where u.id=:id")
    int deleteUserById(@Param("id") Integer id);

    @Modifying
    @Transactional
    @Query("update User u set u.name = :name where u.id=:id")
    int queryUserById(@Param("id") Integer id, @Param("name") String name);

    /* =========================== 分页查询等 =========================== */
    /**
     * 根据表名, 字段, 参数查询, 拼接sql语句
     * @param  tableName 表名
     * @param filed 字段名
     * @param o 字段参数
     */
    List<User> findByHql(String tableName, String filed, Object o);

    Object findObjiectByHql(String tableName, String filed, Object o);

    /**
     * 多个字段的查询
     * @param tableName 表名
     * @param map 将你的字段传入map中
     */
    List<User> findByMoreFiled(String tableName, LinkedHashMap<String, Object> map);

    /**
     * 多字段查询分页
     * @param tableName 表名
     * @param map 以map存储key,value
     * @param star 第几页
     * @param pageNumber 一个页面的条数
     */
    List<User> findByMoreFiledPage(String tableName, LinkedHashMap<String, Object> map, 
                    int star, int pageNumber);

    /**
     * 一个字段的分页
     * @param  tableName 表名
     * @param filed 字段名
     * @param o 字段参数
     * @param start 第几页
     * @param pageNumber 一个页面多少条数据
     */
    List<User> findPages(String tableName, String filed, Object o, int start, int pageNumber);

    /**
     * 根据传入的map遍历key,value拼接字符串, 以id为条件更新
     * @param tableName 表名
     * @param map 传入参数放入map中
     */
    Integer updateMoreFiled(String tableName, LinkedHashMap<String, Object> map, 
                            Long id);

    /**
     * 根据条件查询总条数返回object类型
     * @param tableName  表名
     * @param map 传入参数放入map中
     */
    Object findCount(String tableName, LinkedHashMap<String, Object> map);
}

Service文件

package org.fiend.service;

import com.alibaba.fastjson.JSONObject;
import org.fiend.base.AbstractService;
import org.fiend.entity.User;
import org.fiend.repository.UserRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @author Administrator
 */
@Service
public class HomeService extends AbstractService {
	Logger log = LoggerFactory.getLogger(getClass());

	@Autowired
	private UserRepository userRepository;  

	public JSONObject getUserList() {
		JSONObject json = new JSONObject();
		List<User> userList = userRepository.find();
		json.put("userList", userList);

		return json;
	}

	public JSONObject getUserList1() {
		JSONObject json = new JSONObject();
		List<User> userList = userRepository.findAll();
		json.put("userList", userList);

		return json;
	}

	public List<User> find() {
		List<User> list = null;
		try {
			list = userRepository.find();
		} catch (Exception e) {
		}
		return list;
	}

	public String deleteUserById(Integer id){
		int  a = userRepository.deleteUserById(id);
		return "chenggong";
	}

	public String queryUserById(Integer id ,String name){
		int a = userRepository.queryUserById(id,name);
		return "成功";
	}

	public String countUserBy(Integer id ,String name ,String password){
		int a = userRepository.countUserBy(id,name,password);
		return "成功";
	}
}

Controller文件

package org.fiend.controller;

import com.alibaba.fastjson.JSONObject;
import org.fiend.base.AbstractController;
import org.fiend.service.HomeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.inject.Inject;
import javax.inject.Named;

/**
 * @author Administrator
 */
@Controller
@RequestMapping(value = "home")
public class HomeController extends AbstractController<HomeService> {
	Logger log = LoggerFactory.getLogger(this.getClass());

	@Override
	@Inject
	@Named("homeService")
	protected void setService(HomeService service) {
		this.service = service;
	}

	@RequestMapping(value = "getUserList")
	@ResponseBody
	public JSONObject getUserList() {
		return service.getUserList();
	}

	@RequestMapping(value = "getUserList1")
	@ResponseBody
	public JSONObject getUserList1() {
		return service.getUserList1();
	}
}

运行结果

附录

Repository文件注解说明:

@modifying:
(1)可以通过自定义的JPQL完成UPDATE和DELETE操作。 注意:JPQL不支持使用INSERT;
(2)在@Query注解中编写JPQL语句,但必须使用@Modifying修饰,以通知SpringData这是一个UPDATE 或 DELETE操作
(3)UPDATE 或 DELETE操作需要使用事务,此时需要定义Service层,在Service层的方法上添加事务操作; 
(4)默认情况下,SpringData的每个方法上有事务,但都是一个只读事务。

@Transactional:
A. 一个功能是否要事务,必须纳入设计、编码考虑。不能仅仅完成了基本功能就ok。
B. 如果加了事务,必须做好开发环境测试(测试环境也尽量触发异常、测试回滚),确保事务生效。
C. 以下列了事务使用过程的注意事项,请大家留意。

1.不要在接口上声明@Transactional ,而要在具体类的方法上使用 @Transactional 注解,否则注解可能无效。
2.不要图省事,将@Transactional放置在类级的声明中,放在类声明,会使得所有方法都有事务。
  故@Transactional应该放在方法级别,不需要使用事务的方法,就不要放置事务,比如查询方法。
  否则对性能是有影响的。
3.使用了@Transactional的方法,对同一个类里面的方法调用,
  @Transactional无效。比如有一个类Test,它的一个方法A,A再调用Test本类的方法B
 (不管B是否public还是private),但A没有声明注解事务,而B有。
  则外部调用A之后,B的事务是不会起作用的。(经常在这里出错)

4.使用了@Transactional的方法,只能是public,
  @Transactional注解的方法都是被外部其他类调用才有效,故只能是public。
  道理和上面的有关联。故在protected、private 或者 package-visible 的方法上使用 @Transactional 
  注解,它也不会报错,但事务无效。

5.经过在ICORE-CLAIM中测试,效果如下:
  A.抛出受查异常XXXException,事务会回滚。
  B.抛出运行时异常NullPointerException,事务会回滚。
  C.Quartz中,execute直接调用加了@Transactional方法,可以回滚;
    间接调用,不会回滚。(即上文3点提到的)
  D.异步任务中,execute直接调用加了@Transactional方法,可以回滚;
    间接调用,不会回滚。(即上文3点提到的)
  E.在action中加上@Transactional,不会回滚。切记不要在action中加上事务。
  F.在service中加上@Transactional,如果是action直接调该方法,会回滚,如果是间接调,不会回滚。 
   (即上文3提到的)
  G.在service中的private加上@Transactional,事务不会回滚。

相关文章