• Category Archives: Java

创建一个基于SpringBoot2.1.x的JavaFX程序

1.创建SpringBoot项目

到 https://start.spring.io/ 创建一个SpringBoot2.1.x项目,解压后使用MyEclipse2015导入为maven项目~

2.引入JavaFX

对SpringBoot入口程序Application进行改造,继承javafx的application类,并引入接口CommandLineRunner, Consumer<Stage>,接着加入如下代码(高亮部分):

package com.dgzq;

import java.util.function.Consumer;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TabPane.TabClosingPolicy;
import javafx.stage.Stage;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DgzqApplication extends Application implements CommandLineRunner, Consumer<Stage>{

	public static void main(String[] args) {
		SpringApplication.run(DgzqApplication.class, args);
	}
	
	@Override
	public void run(String... args) throws Exception {
		
		Platform.runLater(new Runnable() {
		    @Override
		    public void run() {
		    	
		    	Stage stage = new Stage();
        		
		    	try {
					start(stage);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
        		
		    }
		});
		
	}

	@Override
	public void start(Stage primaryStage) throws Exception {
		accept(primaryStage);
	}

	@Override
	public void accept(Stage stage) {
		
		TabPane tabPane = new TabPane();	//增加标签面板
		tabPane.setTabClosingPolicy(TabClosingPolicy.UNAVAILABLE);
		
		Scene scene = new Scene(tabPane, 900, 690);
		stage.setScene(scene);
		stage.setTitle("测试界面");
		
		Tab tab1 = new Tab("标签页1");
		Tab tab2 = new Tab("标签页2");
		tabPane.getTabs().addAll(tab1,tab2);
		tabPane.getSelectionModel().select(tab1);	//设置默认选中
		
		stage.show();
	}

}

然后启动,出现如下界面则为成功:

ac571e727fe9d73b3500c54a3e2117c

 

3.增加预加载页面

在pom.xml加入如下依赖:

		<!-- SpringBoot2.x与JavaFX的集成 -->
		<!-- https://mvnrepository.com/artifact/de.roskenet/springboot-javafx-support -->
		<dependency>
		    <groupId>de.roskenet</groupId>
		    <artifactId>springboot-javafx-support</artifactId>
		    <version>2.1.6</version>
		</dependency>

 

新增一个启动入口文件如MainApplication.java用于展示欢迎界面,代码如下:

package com.dgzq;

import java.io.File;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import de.felixroske.jfxsupport.AbstractJavaFxApplicationSupport;
import de.felixroske.jfxsupport.SplashScreen;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.scene.paint.Color;

@SpringBootApplication
public class MainApplication extends AbstractJavaFxApplicationSupport {
	
	public static SplashScreen splashScreen;
	public static Stage splashStage;
	public static Scene splashScene;
	
    public static void main(String[] args) {
    	
    	//启动(若需要以fxml形式展示主界面,则第二个传参可以为"MainStageView.class"之类的)
    	launch(MainApplication.class, null, args);
        
    }

    @Override
    public void start(Stage stage) throws Exception {

    	MainApplication.splashScreen = new SplashScreen();
    	MainApplication.splashStage = new Stage(StageStyle.TRANSPARENT);
    	MainApplication.splashScene = new Scene(splashScreen.getParent(), Color.TRANSPARENT);
    	MainApplication.splashStage.setScene(splashScene);
    	MainApplication.splashStage.initStyle(StageStyle.TRANSPARENT);
    	MainApplication.splashStage.show();

    }
    
}

在预加载完成后还要再正式界面中隐藏掉本界面,因此要在原来的application类的stage.show()前面加入如下代码:

MainApplication.splashStage.hide();
MainApplication.splashStage.setScene(null);

然后注释掉原来的application启动类中的main方法:

/*public static void main(String[] args) {
	SpringApplication.run(DgzqApplication.class, args);
}*/

最后启动刚刚新建的MainApplication.java,便会出现中间界面:

d294a0cca4b571832aaa7b9c70f8363

好了,大功告成。如果还需要引入sqlite数据库,则可以继续往下操作。

4.引入hibernate并使用sqlite数据库

在MainApplication中的 下方加入如下代码,以提示sqlite是否存在:

    	File databaseFile = new File("sqlite3.db");
    	if(!databaseFile.exists()){
	    	Alert alert = new Alert(Alert.AlertType.INFORMATION);
			alert.setTitle("错误");
			alert.setHeaderText(null);
			alert.setContentText("找不到数据库文件:sqlite3.db(本次运行将自动创建全新的空白数据库)");
			alert.showAndWait();
    	}

再pom.xml中加入如下依赖:

	<!-- sqlite3驱动包 -->
        <!-- https://mvnrepository.com/artifact/org.xerial/sqlite-jdbc -->
		<dependency>
		    <groupId>org.xerial</groupId>
		    <artifactId>sqlite-jdbc</artifactId>
		    <version>3.28.0</version>
		</dependency>
		
		<!-- SpringBoot与hibernate的集成配置 -->
		<dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<!-- SpringBoot使用Hibernate的SessionFactory -->
		<dependency>
		    <groupId>org.hibernate</groupId>
		    <artifactId>hibernate-core</artifactId>
		    <version>5.0.12.Final</version>
		</dependency>
		<dependency>
		    <groupId>org.hibernate</groupId>
		    <artifactId>hibernate-entitymanager</artifactId>
		    <version>5.0.12.Final</version>
		</dependency>
		
		<!-- SpringBoot2.x与JavaFX的集成 -->
		<!-- https://mvnrepository.com/artifact/de.roskenet/springboot-javafx-support -->
		<dependency>
		    <groupId>de.roskenet</groupId>
		    <artifactId>springboot-javafx-support</artifactId>
		    <version>2.1.6</version>
		</dependency>

 

对原来的Application进行修改(加入高亮部分):

package com.dgzq;

import java.util.function.Consumer;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TabPane.TabClosingPolicy;
import javafx.stage.Stage;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.orm.jpa.vendor.HibernateJpaSessionFactoryBean;

@SpringBootApplication
public class DgzqApplication extends Application implements CommandLineRunner, Consumer<Stage>{
	
	public static SessionFactory sessionFactory;
	@Autowired
	public void setSessionFactory(SessionFactory sessionFactory) {
		DgzqApplication.sessionFactory = sessionFactory;
	}
	
	@Bean
    public HibernateJpaSessionFactoryBean sessionFactory() {
        return new HibernateJpaSessionFactoryBean();
    }

	/*public static void main(String[] args) {
		SpringApplication.run(DgzqApplication.class, args);
	}*/
	
	@Override
	public void run(String... args) throws Exception {
		
		Platform.runLater(new Runnable() {
		    @Override
		    public void run() {
		    	
		    	Stage stage = new Stage();
        		
		    	try {
					start(stage);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
        		
		    }
		});
		
	}

	@Override
	public void start(Stage primaryStage) throws Exception {
		accept(primaryStage);
	}

	@Override
	public void accept(Stage stage) {
		
		System.out.println("MainJavaFxApplication被实例化了");
		System.out.println("MainJavaFxApplication.sessionFactory = "+sessionFactory);
		
		TabPane tabPane = new TabPane();	//增加标签面板
		tabPane.setTabClosingPolicy(TabClosingPolicy.UNAVAILABLE);
		
		Scene scene = new Scene(tabPane, 900, 690);
		stage.setScene(scene);
		stage.setTitle("测试界面");
		
		Tab tab1 = new Tab("标签页1");
		Tab tab2 = new Tab("标签页2");
		tabPane.getTabs().addAll(tab1,tab2);
		tabPane.getSelectionModel().select(tab1);	//设置默认选中
		
		MainApplication.splashStage.hide();
		MainApplication.splashStage.setScene(null);
		
		stage.show();
	}

}

增加sqlite的方言类SQLiteDialect.java:

package com.fenji;

import java.sql.Types;

import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.function.StandardSQLFunction;
import org.hibernate.dialect.function.SQLFunctionTemplate;
import org.hibernate.dialect.function.VarArgsSQLFunction;
import org.hibernate.type.StandardBasicTypes;

public class SQLiteDialect extends Dialect {
    public SQLiteDialect() {
        super();
        registerColumnType(Types.BIT, "integer");
        registerColumnType(Types.TINYINT, "tinyint");
        registerColumnType(Types.SMALLINT, "smallint");
        registerColumnType(Types.INTEGER, "integer");
        registerColumnType(Types.BIGINT, "bigint");
        registerColumnType(Types.FLOAT, "float");
        registerColumnType(Types.REAL, "real");
        registerColumnType(Types.DOUBLE, "double");
        registerColumnType(Types.NUMERIC, "numeric");
        registerColumnType(Types.DECIMAL, "decimal");
        registerColumnType(Types.CHAR, "char");
        registerColumnType(Types.VARCHAR, "varchar");
        registerColumnType(Types.LONGVARCHAR, "longvarchar");
        registerColumnType(Types.DATE, "date");
        registerColumnType(Types.TIME, "time");
        registerColumnType(Types.TIMESTAMP, "timestamp");
        registerColumnType(Types.BINARY, "blob");
        registerColumnType(Types.VARBINARY, "blob");
        registerColumnType(Types.LONGVARBINARY, "blob");
        // registerColumnType(Types.NULL, "null");
        registerColumnType(Types.BLOB, "blob");
        registerColumnType(Types.CLOB, "clob");
        registerColumnType(Types.BOOLEAN, "integer");

        registerFunction("concat", new VarArgsSQLFunction(StandardBasicTypes.STRING, "", "||", ""));
        registerFunction("mod", new SQLFunctionTemplate(StandardBasicTypes.INTEGER, "?1 % ?2"));
        registerFunction("substr", new StandardSQLFunction("substr", StandardBasicTypes.STRING));
        registerFunction("substring", new StandardSQLFunction("substr", StandardBasicTypes.STRING));
    }

    public boolean supportsIdentityColumns() {
        return true;
    }

    public boolean hasDataTypeInIdentityColumn() {
        return false;
    }

    public String getIdentityColumnString() {
        return "integer";
    }

    public String getIdentitySelectString() {
        return "select last_insert_rowid()";
    }

    public boolean supportsLimit() {
        return true;
    }

    public String getLimitString(String query, boolean hasOffset) {
        return new StringBuffer(query.length() + 20).append(query).append(hasOffset ? " limit ? offset ?" : " limit ?")
                .toString();
    }

    public boolean supportsTemporaryTables() {
        return true;
    }

    public String getCreateTemporaryTableString() {
        return "create temporary table if not exists";
    }

    public boolean dropTemporaryTableAfterUse() {
        return false;
    }

    public boolean supportsCurrentTimestampSelection() {
        return true;
    }

    public boolean isCurrentTimestampSelectStringCallable() {
        return false;
    }

    public String getCurrentTimestampSelectString() {
        return "select current_timestamp";
    }

    public boolean supportsUnionAll() {
        return true;
    }

    public boolean hasAlterTable() {
        return false;
    }

    public boolean dropConstraints() {
        return false;
    }

    public String getAddColumnString() {
        return "add column";
    }

    public String getForUpdateString() {
        return "";
    }

    public boolean supportsOuterJoinForUpdate() {
        return false;
    }

    public String getDropForeignKeyString() {
        throw new UnsupportedOperationException("No drop foreign key syntax supported by SQLiteDialect");
    }

    public String getAddForeignKeyConstraintString(String constraintName, String[] foreignKey, String referencedTable,
            String[] primaryKey, boolean referencesPrimaryKey) {
        throw new UnsupportedOperationException("No add foreign key syntax supported by SQLiteDialect");
    }

    public String getAddPrimaryKeyConstraintString(String constraintName) {
        throw new UnsupportedOperationException("No add primary key syntax supported by SQLiteDialect");
    }

    public boolean supportsIfExistsBeforeTableName() {
        return true;
    }

    public boolean supportsCascadeDelete() {
        return false;
    }

    @Override
    public boolean bindLimitParametersInReverseOrder() {
        return true;
    }
}

增加配置文件application.properties用于配置数据库(注意高亮行,要指向刚刚创建的方言类SQLiteDialect.java):

spring.datasource.driver-class-name=org.sqlite.JDBC
spring.datasource.url=jdbc:sqlite:sqlite3.db

# Specify the DBMS
#spring.jpa.database=SQLite
# Show or not log for each sql query
spring.jpa.show-sql=true
# Hibernate ddl auto (create, create-drop, update)
spring.jpa.hibernate.ddl-auto=update
# Naming strategy
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy
# stripped before adding them to the entity manager
#spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.dialect=com.dgzq.SQLiteDialect
# table column upcase problem
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
# auto inject sessionFactory bean
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext

好了,运行MainApplication看看效果:

639fccfb32a10d16ee5a29089e0094f

如图所示,输入sessionFactory不为空,则注入成功,后面大家自由发挥吧!

5.补充:记得指定maven打包时的启动入口

在pom.xml中加入如下高亮代码

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<mainClass>com.dgzq.MainApplication</mainClass>
				</configuration>
			</plugin>
		</plugins>
	</build>

大功告成!

当在SpringBoot使用Redis的Session共享功能时,@EnableScheduling始终生效的问题。

我在调试项目的redis共享时,遇到了这种情况:

当我需要使用Redis来管理SpringBoot的Session时,会加入如下依赖:

		<dependency>
			<groupId>org.springframework.session</groupId>
			<artifactId>spring-session-data-redis</artifactId>
		</dependency>

这个依赖会让启动类中的@EnableScheduling设定无效,就是说,此时无论有没有@EnableScheduling,系统中的所有定时器均会生效。

唉~具体原因,我猜是因为这个功能需要用到定时器,所以会默认开启了呗~折腾了我半天,真浪费时间~

SpringBoot2.1.1整合hibernate5.0.12使用SessionFactory

1、在pom.xml中加入如下依赖:

		<!-- Spring的aspect切面支持 -->
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-aspects</artifactId>
		    <version>4.2.5.RELEASE</version>
		</dependency>

		<!-- Spring的ORM(Hibernate)映射支持 -->
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-orm -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-orm</artifactId>
		    <!-- <version>5.0.12.RELEASE</version>
		    <version>4.3.11.RELEASE</version> -->
		    <version>4.2.5.RELEASE</version>
		</dependency>

		<!-- Spring对Hibernate-SessionFactory的事务管理支持 -->
		<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
		<dependency>
		    <groupId>org.hibernate</groupId>
		    <artifactId>hibernate-core</artifactId>
		    <version>5.0.12.Final</version>
		</dependency>

		<!-- mysql连接驱动 -->    
		<dependency>    
			<groupId>mysql</groupId>    
			<artifactId>mysql-connector-java</artifactId>    
			<version>5.1.9</version>
		</dependency>

如果pom.xml中有如下jpa依赖,记得清注释以下内容:

		<!-- SpringBoot对JPA的支持 -->
		<!-- <dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency> -->

如果出现FilterRegistrationBean报错,则意味着缺少SpringMVC的filter依赖,办法之一是引入含有该filter的依赖(eureka的server依赖也是包含的):

		<!-- SpringMVC的配置 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
	        	<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

 

2、在application.properties中加入如下配置:

#mysql
spring.datasource.url=jdbc\:mysql\://localhost\:3306/xxxxx?useSSL\=false&characterEncoding\=utf8
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

如果在低版本SpringBoot中进行配置,则可能会遇到错误“Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true”,此时则需要在application.properties补充配置:

spring.main.allow-bean-definition-overriding=true

因为SpringBoot的SessionFactory会自动注入默认的Transactional事务管理器,但这个事务管理器搭配hibernate的SessionFactory会出现数据库连接池线程卡死的问题,即假如配置线程池的连接数为10,一旦连接数大于10,则线程池会出现卡死的情况,因此我们需要自行配置hibernate的事务管理器来覆盖SpringBoot原有的Transactional事务管理器。

3、在SpringBoot的启动入口类上加入注解@ImportResource(“classpath:hibernate.xml”):

@SpringBootApplication
@ImportResource("classpath:hibernate.xml")
public class xxxxxApplication extends SpringBootServletInitializer{

	public static void main(String[] args) {
		SpringApplication.run(xxxxxApplication.class, args);
	}

}

4、在resources目录中加入配置文件hibernate.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util"
	xmlns:tool="http://www.springframework.org/schema/tool" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/tx
           http://www.springframework.org/schema/tx/spring-tx.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop.xsd
           http://www.springframework.org/schema/jee
           http://www.springframework.org/schema/jee/spring-jee.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/util
           http://www.springframework.org/schema/util/spring-util.xsd
           http://www.springframework.org/schema/tool
           http://www.springframework.org/schema/tool/spring-tool.xsd"
    default-autowire="no">
	
	<!-- hibernate sessionFactory 创建 -->
	<!-- hibernate.cfg.xml Spring config -->
	<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
		<!-- connection -->
		<property name="dataSource">
			<ref bean="dataSource" />
		</property>
		<!-- hibernate 类文件配置 -->
		<!-- hibernate自身属性 -->
		<property name="hibernateProperties">
			<props>
				<!-- 显示Hibernate 持久化操作所生成的SQL -->
				<prop key="hibernate.show_sql">false</prop>
				<!-- 将SQL脚本进行格式化后在输出 -->
				<prop key="hibernate.format_sql">true</prop>
				<!-- 指定数据库方言 -->
				<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
				<!-- **************** -->
				<prop key="hibernate.hbm2ddl.auto">update</prop>
				<!-- 解决no session found -->
				<!-- <prop key="hibernate.current_session_context_class">thread</prop> -->
				
				<!-- <prop key="hibernate.cache.use_second_level_cache">true</prop> -->
				<!-- hibernate4的二级缓存配置 -->
				<!-- <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop> -->
				<!-- hibernate3的二级缓存配置 -->
				<!-- <prop name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> -->
        		<!-- 开启查询缓存 -->
				<!-- <prop key="hibernate.cache.use_query_cache">true</prop> -->
				
			</props>
		</property>
		<!-- 自动扫描注解方式配置的hibernate类文件 -->
		<property name="packagesToScan">
			<list>
				<value>com.zero4j.model</value>
			</list>
		</property>
		<!-- 手动加载配置映射文件 -->
		<property name="mappingResources">
			<list>
				<!-- <value>com/***/model/order/Order.hbm.xml</value> -->
			</list>
		</property>
		<!-- 手动加载注解类映射文件-->
		<!-- <property name="annotatedClasses">
			<list>
				<value>com.zero4j.model.test.Test</value>
			</list>
		</property> -->
	</bean>

	<!-- 开启注解事务 只对当前配置文件有效 -->
  	<tx:annotation-driven transaction-manager="txManager"/>
	<bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        	<property name="sessionFactory" ref="sessionFactory"/>
   	</bean>

</beans>

5、增加事务管理配置,有两种方式,一种是使用SpringBoot的config注入方式,另外一种是加在hibernate.xml中。(记住下面5.1和5.2是二选一)

5.1、使用SpringBoot的confiug注入方式:增加配置文件TransactionAdviceConfig.java:

package com.isuidian.config;


import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;

@Aspect
@Configuration
public class TransactionAdviceConfig {

	 //使dao使用session
	private static final String AOP_POINTCUT_EXPRESSION = " (execution(* com..dao..*.*(..))) ";
	//controller由过滤器中进行设置,这里设置会抽风
	/*private static final String AOP_POINTCUT_EXPRESSION2 = " (execution(* com..controller..*.*(..))) ";*/
	 
	 
    @Autowired
    private PlatformTransactionManager transactionManager;

    @Bean
    public TransactionInterceptor txAdvice() {

        DefaultTransactionAttribute txAttr_REQUIRED = new DefaultTransactionAttribute();
        txAttr_REQUIRED.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

        DefaultTransactionAttribute txAttr_REQUIRED_READONLY = new DefaultTransactionAttribute();
        txAttr_REQUIRED_READONLY.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        txAttr_REQUIRED_READONLY.setReadOnly(true);
        
        
        DefaultTransactionAttribute txAttr_READONLY = new DefaultTransactionAttribute();
        txAttr_READONLY.setReadOnly(true);
        
        

        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();

        source.addTransactionalMethod("save*", txAttr_REQUIRED);
        source.addTransactionalMethod("add*", txAttr_REQUIRED);
        source.addTransactionalMethod("create*", txAttr_REQUIRED);
        source.addTransactionalMethod("insert*", txAttr_REQUIRED);
        source.addTransactionalMethod("update*", txAttr_REQUIRED);
        source.addTransactionalMethod("merge*", txAttr_REQUIRED);
        source.addTransactionalMethod("del*", txAttr_REQUIRED);
        source.addTransactionalMethod("remove*", txAttr_REQUIRED);
        source.addTransactionalMethod("put*", txAttr_REQUIRED);
        source.addTransactionalMethod("use*", txAttr_REQUIRED);
        source.addTransactionalMethod("exec*", txAttr_REQUIRED);
        source.addTransactionalMethod("set*", txAttr_REQUIRED);
        
        
        source.addTransactionalMethod("get*", txAttr_REQUIRED_READONLY);//特殊,service在save后会重新读取,如果设置成REQUIRED_READONLY,则save不会保存数据
        source.addTransactionalMethod("count*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("find*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("list*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("query*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("find*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("is*", txAttr_REQUIRED_READONLY);
        
        /*
        source.addTransactionalMethod("save*", txAttr_REQUIRED);
        source.addTransactionalMethod("delete*", txAttr_REQUIRED);
        source.addTransactionalMethod("update*", txAttr_REQUIRED);
        source.addTransactionalMethod("exec*", txAttr_REQUIRED);
        source.addTransactionalMethod("set*", txAttr_REQUIRED);
        source.addTransactionalMethod("get*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("query*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("find*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("list*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("count*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("is*", txAttr_REQUIRED_READONLY);
        
        */
        source.addTransactionalMethod("*", txAttr_READONLY);
        return new TransactionInterceptor(transactionManager, source);
    }

    @Bean
    public Advisor txAdviceAdvisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression( AOP_POINTCUT_EXPRESSION );
        return new DefaultPointcutAdvisor(pointcut, txAdvice());
    }
    
   /* @Bean
    public Advisor txAdviceAdvisor2() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression( AOP_POINTCUT_EXPRESSION2 );
        return new DefaultPointcutAdvisor(pointcut, txAdvice());
    }*/
}

5.2、加在hibernate.xml中:

    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="save*" propagation="REQUIRED" />
            <tx:method name="add*" propagation="REQUIRED" />
            <tx:method name="create*" propagation="REQUIRED" />
            <tx:method name="insert*" propagation="REQUIRED" />
            <tx:method name="update*" propagation="REQUIRED" />
            <tx:method name="merge*" propagation="REQUIRED" />
            <tx:method name="del*" propagation="REQUIRED" />
            <tx:method name="remove*" propagation="REQUIRED" />
            <tx:method name="put*" propagation="REQUIRED" />
            <tx:method name="use*" propagation="REQUIRED"/>
            <!--hibernate4必须配置为开启事务 否则 getCurrentSession()获取不到-->
            <tx:method name="get*" propagation="REQUIRED" read-only="true" />
            <tx:method name="count*" propagation="REQUIRED" read-only="true" />
            <tx:method name="find*" propagation="REQUIRED" read-only="true" />
            <tx:method name="list*" propagation="REQUIRED" read-only="true" />
            <tx:method name="*" read-only="true" />
        </tx:attributes>
    </tx:advice>

 

6、增加事务管理过滤器FilterConfig.java,自动开启事务管理:

package com.isuidian.config;


import org.aspectj.lang.annotation.Aspect;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.hibernate5.support.OpenSessionInViewFilter;

@Aspect
@Configuration
public class FilterConfig {

	//解决调用接口时session抽风的问题
	@Bean
	public FilterRegistrationBean<OpenSessionInViewFilter> testFilterRegistration() {	
		FilterRegistrationBean<OpenSessionInViewFilter> registration = new FilterRegistrationBean<>();
		registration.setFilter(new OpenSessionInViewFilter());
		registration.addUrlPatterns("/*");//配置过滤路径
		return registration;
	}
	
}

7、搞掂,启动项目!在需要使用SessionFactory的地方使用如下方式注入即可:

@Autowired
private SessionFactory sessionFactory;

 

常见问题

重复的依赖错误

错误提示如下:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Unsatisfied dependency expressed through method 'entityManagerFactory' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'entityManagerFactoryBuilder' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Unsatisfied dependency expressed through method 'entityManagerFactoryBuilder' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaVendorAdapter' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.JpaVendorAdapter]: Factory method 'jpaVendorAdapter' threw exception; nested exception is java.lang.NoSuchFieldError: HANA
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:769) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:509) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1288) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1127) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1083) ~[spring-context-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:853) ~[spring-context-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546) ~[spring-context-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) ~[spring-boot-2.1.1.RELEASE.jar:2.1.1.RELEASE]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) [spring-boot-2.1.1.RELEASE.jar:2.1.1.RELEASE]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.1.1.RELEASE.jar:2.1.1.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) [spring-boot-2.1.1.RELEASE.jar:2.1.1.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) [spring-boot-2.1.1.RELEASE.jar:2.1.1.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) [spring-boot-2.1.1.RELEASE.jar:2.1.1.RELEASE]
	at com.gushing.GushingApplication.main(GushingApplication.java:29) [classes/:na]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_201]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_201]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_201]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_201]
	at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-2.1.1.RELEASE.jar:2.1.1.RELEASE]
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'entityManagerFactoryBuilder' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Unsatisfied dependency expressed through method 'entityManagerFactoryBuilder' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaVendorAdapter' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.JpaVendorAdapter]: Factory method 'jpaVendorAdapter' threw exception; nested exception is java.lang.NoSuchFieldError: HANA
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:769) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:509) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1288) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1127) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:273) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1237) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1164) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	... 24 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaVendorAdapter' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.JpaVendorAdapter]: Factory method 'jpaVendorAdapter' threw exception; nested exception is java.lang.NoSuchFieldError: HANA
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:627) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:456) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1288) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1127) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:273) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1237) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1164) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	... 38 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.JpaVendorAdapter]: Factory method 'jpaVendorAdapter' threw exception; nested exception is java.lang.NoSuchFieldError: HANA
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:622) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	... 52 common frames omitted
Caused by: java.lang.NoSuchFieldError: HANA
	at org.springframework.boot.autoconfigure.orm.jpa.DatabaseLookup.<clinit>(DatabaseLookup.java:56) ~[spring-boot-autoconfigure-2.1.1.RELEASE.jar:2.1.1.RELEASE]
	at org.springframework.boot.autoconfigure.orm.jpa.JpaProperties.determineDatabase(JpaProperties.java:142) ~[spring-boot-autoconfigure-2.1.1.RELEASE.jar:2.1.1.RELEASE]
	at org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration.jpaVendorAdapter(JpaBaseConfiguration.java:112) ~[spring-boot-autoconfigure-2.1.1.RELEASE.jar:2.1.1.RELEASE]
	at org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration$$EnhancerBySpringCGLIB$$f91d7855.CGLIB$jpaVendorAdapter$4(<generated>) ~[spring-boot-autoconfigure-2.1.1.RELEASE.jar:2.1.1.RELEASE]
	at org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration$$EnhancerBySpringCGLIB$$f91d7855$$FastClassBySpringCGLIB$$292a616.invoke(<generated>) ~[spring-boot-autoconfigure-2.1.1.RELEASE.jar:2.1.1.RELEASE]
	at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) ~[spring-core-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363) ~[spring-context-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration$$EnhancerBySpringCGLIB$$f91d7855.jpaVendorAdapter(<generated>) ~[spring-boot-autoconfigure-2.1.1.RELEASE.jar:2.1.1.RELEASE]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_201]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_201]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_201]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_201]
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	... 53 common frames omitted

这很有可能你的依赖中有重复的内容,如:

		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-entitymanager</artifactId>
			<version>${hibernate.version}</version>
		</dependency>

这个是需要注释掉的,不然会报错。

在SpringBoot中使用SessionFactory的方法

首先项目中已经使用JPA的方式连接,然后加入hibernate依赖:

	<properties>
		<java.version>1.8</java.version>
		<hibernate.version>5.0.12.Final</hibernate.version>
	</properties>
		<!-- SpringBoot使用Hibernate的SessionFactory -->
		<dependency>
		    <groupId>org.hibernate</groupId>
		    <artifactId>hibernate-core</artifactId>
		    <version>${hibernate.version}</version>
		</dependency>
		<dependency>
		    <groupId>org.hibernate</groupId>
		    <artifactId>hibernate-entitymanager</artifactId>
		    <version>${hibernate.version}</version>
		</dependency>

 

然后有以下几种方式,选择一种合适自己的。

方法一:

增加配置文件HibernateConfig.java:

package com.testSSH.config;

import javax.persistence.EntityManagerFactory;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class HibernateConfig {
    
    @Bean
    public SessionFactory sessionFactory(@Qualifier("entityManagerFactory") EntityManagerFactory emf){
         return emf.unwrap(SessionFactory.class);
     }

}

如果要使用@Transactional则需要在application.properties中加上:

spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext

 

方法二:(推荐)

在SpringBoot的启动类中加上:

	@Bean
	public SessionFactory sessionFactory(HibernateEntityManagerFactory hemf) {
	    return hemf.getSessionFactory();
	}

如果要使用@Transactional则需要在application.properties中加上:

spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext

 

 

方法三:

在SpringBoot的启动类中加上:

    @Bean
    public HibernateJpaSessionFactoryBean sessionFactory() {
        return new HibernateJpaSessionFactoryBean();
    }

如果要使用@Transactional则需要在application.properties中加上:

spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext

 

 

使用方法:

@Autowired
private SessionFactory sessionFactory;

 

让SpringBoot2.0不使用hiraki数据库连接池而改用c3p0

SpringBoot2.0默认是用hiraki数据库连接池,听说这个是当今运行效率最高的,但由于某些原因我要使用c3p0数据库连接池,所以就给大家说一下我的配置过程,其实还是挺简单的:

在pom.xml中加上依赖:

		<!-- 不使用默认的hikari数据库连接池,使用c3p0的 -->
		<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
		<dependency>
		    <groupId>com.mchange</groupId>
		    <artifactId>c3p0</artifactId>
		    <version>0.9.5.4</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/com.mchange/mchange-commons-java -->
		<dependency>
		    <groupId>com.mchange</groupId>
		    <artifactId>mchange-commons-java</artifactId>
		    <version>0.2.15</version>
		</dependency>

然后注释掉原来application.properties中的默认数据库配置而改用c3p0的:

#mysql
#spring.datasource.url=jdbc\:mysql\://localhost\:3306/test?useSSL\=false&characterEncoding\=utf8
#spring.datasource.username=test
#spring.datasource.password=test
#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#spring.datasource.hikari.minimum-idle=10
#spring.datasource.hikari.maximum-pool-size=50

# c3p0
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/test?autoReconnect=true&amp;autoReconnectForPools=true&amp;useUnicode=true&amp;characterEncoding=utf-8
c3p0.user=test
c3p0.password=test
c3p0.driverClass=com.mysql.jdbc.Driver
#c3p0.minPoolSize=2
#c3p0.maxPoolSize=100
#c3p0.maxIdleTime=0
#c3p0.acquireIncrement=3
#c3p0.maxStatements=1000
#c3p0.initialPoolSize=3
#c3p0.idleConnectionTestPeriod=60
#c3p0.acquireRetryAttempts=30
#c3p0.acquireRetryDelay=1000
#c3p0.breakAfterAcquireFailure=false
#c3p0.testConnectionOnCheckout=false

最后补充配置类:

package com.isuidian.config;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;

@Configuration
public class DataSourceConfiguration {
 
    // c3p0 连接池
    @Bean(name = "dataSource")
    @Qualifier(value = "dataSource")
    @Primary
    @ConfigurationProperties(prefix = "c3p0")
    public DataSource dataSource(@Autowired Environment environment) {
        return DataSourceBuilder.create().type(com.mchange.v2.c3p0.ComboPooledDataSource.class).build();
    }
}

搞掂,部署运行,在springboot的启动信息中可以看到c3p0已经生效了。

SpringBoot2.0+Hibernate在Controller使用Session并发性能调优

从SpringBoot2.0开始,其DataSource就交给了Hikari负责。

对于高并发需求,根据数据库的性能,若然Controller执行时间过长,过多controller正在等待有限的sessionFactory资源,则会造成线程堵塞,引起雪崩。

需要在springboot的配置中假如如下设置:

spring.datasource.hikari.minimum-idle=10
spring.datasource.hikari.maximum-pool-size=50
spring.datasource.hikari.idle-timeout=20000
spring.datasource.hikari.connection-timeout=20000

最主要是maximum-pool-size参数,在不设置的情况下默认是10,所以当用户卡在controller等待使用session资源时,做并发测试的时候就会出现卡死现象,引起雪崩。

如果controller中关于数据查询的部分的执行时间较长,maximum-pool-size一定要调大,但是这个值越大我猜测就越内存,一定要适当。

SpringBoot2.1.x+SpringCloud:Eureka(server+client)入门+高可用配置

eureka

一、Eureka服务器+Eureka服务提供者

1、首先到https://start.spring.io/中创建版本为2.1.x项目,在本地的IDEA导入后,首先在pom.xml中增加以下依赖(在pom.xml的<dependencies></dependencies>之间):

<!--Netflix Eureka依赖-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

2、然后在pom.xml的<project></project>之间增加以下关于springcloud的版本管理:

<dependencyManagement>
	<dependencies>
		<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-dependencies</artifactId>
		<version>${spring-cloud.version}</version>
		<type>pom</type>
		<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

3、接着在在pom.xml的<properties></properties>中增加以下配置(注意:Greenwich对应的是springboot2.1.x版本,如果换成其他的会报错,就这个坑把我坑了一个下午):

<spring-cloud.version>Greenwich.SR3</spring-cloud.version>

4、还有在application.properties中增加如下配置:

1)eureka服务器是这样配置的:

server.port=8761

spring.application.name=eureka-server-1

#注册的域名(注意:可以使用localhost,但在高可用时,不同的eureka-server必须要使用不同的hostname,否则无法相互发现)
eureka.instance.hostname=eureka-server-1
#是否向注册中心注册自己(非高可用时为false,高可用时为true)
eureka.client.registerWithEureka=true
#是否从eureka上获取信息(非高可用时为false,高可用时为true)
eureka.client.fetchRegistry=true
#eureka通信地址(非高可用时写自己的eureka-server地址,高可用时填高可用的目标eureka-server地址)
eureka.client.serviceUrl.defaultZone=http\://eureka-server-2\:8762/eureka/

2)eureka服务提供者是这样配置的:

server.port=8771

spring.application.name=client1

eureka.instance.prefer-ip-address=true
#多个eureka-server时可用","号分隔
eureka.client.serviceUrl.defaultZone=http\://localhost\:8761/eureka/

5、最后在springboot的启动文件xxxApplication.java中增加对应的注解:

1)eureka服务器要使用@EnableEurekaServer注解:

package com.zero4j.eurekaserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {

	public static void main(String[] args) {
		SpringApplication.run(EurekaServerApplication.class, args);
	}

}

2)eureka服务器要使用@EurekaClient1Application注解:

package com.zero4j.eurekaclient1;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient   //也可以用EnableDiscoveryClient代替,前者兼容性更大,后者仅能兼容Eureka
public class EurekaClient1Application {

	public static void main(String[] args) {
		SpringApplication.run(EurekaClient1Application.class, args);
	}

}

 

访问eureka-server对应的端口,将会显示以下是最终的运行结果:

123

 

二、Eureka服务消费者的相关配置

1、首先到https://start.spring.io/中创建版本为2.1.x项目,在本地的IDEA导入后,首先在pom.xml中增加以下依赖(在pom.xml的<dependencies></dependencies>之间):

<!--Netflix Eureka依赖-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

2、然后在pom.xml的<project></project>之间增加以下关于springcloud的版本管理:

<dependencyManagement>
	<dependencies>
		<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-dependencies</artifactId>
		<version>${spring-cloud.version}</version>
		<type>pom</type>
		<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

3、接着在在pom.xml的<properties></properties>中增加以下配置(注意:Greenwich对应的是springboot2.1.x版本,如果换成其他的会报错,就这个坑把我坑了一个下午):

<spring-cloud.version>Greenwich.SR3</spring-cloud.version>

4、还有在application.properties中增加如下配置:

#消费者端口
server.port=8081
spring.application.name=eureka-consumer-1
eureka.instance.hostname=localhost
eureka.client.service-url.defaultZone=http\://localhost\:8761/eureka/,http\://localhost\:8762/eureka/

5、创建RestTemplate模板配置

package com.zero4j.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {
	
	/**
     * RestTemplate:提供了多种便捷访问远程Http服务的方法
     * 是一种简单便捷访问Restful服务模板类,提供用于访问Rest服务的客户端模板类
     */
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
    
}

6、消费者调用eureka服务示例

package com.zero4j.controller;

import java.util.Random;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("/")
public class TestControllerProvider {
	
	@Autowired
    private RestTemplate restTemplate;

	@GetMapping("/test")
    public String test() {
		
		//通过服务提供者名称调用
		//List<Dept> depts = restTemplate.getForObject("http://wzx-spring-cloud-provider/dept/findAll", List.class);
		//return depts;
		
		String test = restTemplate.getForObject("http://eureka-client-1/test", String.class);
		
		return test;
    }
	
}

7、服务提供者的java示例

package com.zero4j.controller;

import java.util.Random;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/")
public class TestControllerProvider {

	@GetMapping("/test")
    public String test() {
        return "服务提供者1:"+String.valueOf((new Random()).nextInt());
    }
	
}

配置SpringBoot的全局事务,解决在Controller中使用SessionFactory必须要使用注解@Transactional的问题

增加以下两个配置文件:

TransactionAdviceConfig.java

package com.zero4j.config;


import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;

@Aspect
@Configuration
public class TransactionAdviceConfig {

	 //使dao使用session
	private static final String AOP_POINTCUT_EXPRESSION = " (execution(* com..dao..*.*(..))) ";
	//controller由过滤器中进行设置,这里设置会抽风
	/*private static final String AOP_POINTCUT_EXPRESSION2 = " (execution(* com..controller..*.*(..))) ";*/
	 
	 
    @Autowired
    private PlatformTransactionManager transactionManager;

    @Bean
    public TransactionInterceptor txAdvice() {

        DefaultTransactionAttribute txAttr_REQUIRED = new DefaultTransactionAttribute();
        txAttr_REQUIRED.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

        DefaultTransactionAttribute txAttr_REQUIRED_READONLY = new DefaultTransactionAttribute();
        txAttr_REQUIRED_READONLY.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        txAttr_REQUIRED_READONLY.setReadOnly(true);
        
        
        DefaultTransactionAttribute txAttr_READONLY = new DefaultTransactionAttribute();
        txAttr_READONLY.setReadOnly(true);
        
        

        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();

        source.addTransactionalMethod("save*", txAttr_REQUIRED);
        source.addTransactionalMethod("add*", txAttr_REQUIRED);
        source.addTransactionalMethod("create*", txAttr_REQUIRED);
        source.addTransactionalMethod("insert*", txAttr_REQUIRED);
        source.addTransactionalMethod("update*", txAttr_REQUIRED);
        source.addTransactionalMethod("merge*", txAttr_REQUIRED);
        source.addTransactionalMethod("del*", txAttr_REQUIRED);
        source.addTransactionalMethod("remove*", txAttr_REQUIRED);
        source.addTransactionalMethod("put*", txAttr_REQUIRED);
        source.addTransactionalMethod("use*", txAttr_REQUIRED);
        source.addTransactionalMethod("exec*", txAttr_REQUIRED);
        source.addTransactionalMethod("set*", txAttr_REQUIRED);
        
        
        source.addTransactionalMethod("get*", txAttr_REQUIRED_READONLY);//特殊,service在save后会重新读取,如果设置成REQUIRED_READONLY,则save不会保存数据
        source.addTransactionalMethod("count*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("find*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("list*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("query*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("find*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("is*", txAttr_REQUIRED_READONLY);
        
        /*
        source.addTransactionalMethod("save*", txAttr_REQUIRED);
        source.addTransactionalMethod("delete*", txAttr_REQUIRED);
        source.addTransactionalMethod("update*", txAttr_REQUIRED);
        source.addTransactionalMethod("exec*", txAttr_REQUIRED);
        source.addTransactionalMethod("set*", txAttr_REQUIRED);
        source.addTransactionalMethod("get*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("query*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("find*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("list*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("count*", txAttr_REQUIRED_READONLY);
        source.addTransactionalMethod("is*", txAttr_REQUIRED_READONLY);
        
        */
        source.addTransactionalMethod("*", txAttr_READONLY);
        return new TransactionInterceptor(transactionManager, source);
    }

    @Bean
    public Advisor txAdviceAdvisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression( AOP_POINTCUT_EXPRESSION );
        return new DefaultPointcutAdvisor(pointcut, txAdvice());
    }
    
   /* @Bean
    public Advisor txAdviceAdvisor2() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression( AOP_POINTCUT_EXPRESSION2 );
        return new DefaultPointcutAdvisor(pointcut, txAdvice());
    }*/
}

FilterConfig.java

package com.zero4j.config;


import org.aspectj.lang.annotation.Aspect;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.hibernate5.support.OpenSessionInViewFilter;

@Aspect
@Configuration
public class FilterConfig {

	//解决调用接口时session抽风的问题
	@Bean
	public FilterRegistrationBean<OpenSessionInViewFilter> testFilterRegistration() {	
		FilterRegistrationBean<OpenSessionInViewFilter> registration = new FilterRegistrationBean<>();
		registration.setFilter(new OpenSessionInViewFilter());
		registration.addUrlPatterns("/*");//配置过滤路径
		return registration;
	}
	
}

 

SpringBoot利用Redis对session进行共享

1、引入pom依赖包

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

2、配置application.application

# spring session使用存储类型
spring.session.store-type=redis

#配置redis集群

spring.redis.cluster.nodes=192.168.1.55:7000,192.168.1.53:7003

3、启动类中增加@EnableRedisHttpSession

4、使用
request.getSession().setAttribute(“username”, “admin”);
String userName = (String) request.getSession().getAttribute(“username”);

close