为了避免持久化的逻辑分散到应用的各个组件中,将数据访问功能放到一个或多个专注于此项任务的组件中,这样的组件通常称为数据访问对象(DAO)或Repository。

为了避免应用与特定的数据访问策略耦合在一起,编写良好的Repository应该以借口的方式暴漏功能。通过接口来访问Repository可以为这些数据访问接口创建mock实现,提升单元测试的效率。

SQLException表示在尝试访问数据库时出现了问题,但这个异常却没有告诉你哪里出错了以及如何进行处理。

可能导致抛出SQLException的常见问题包括:应用程序无法连接数据库;要执行查询存在语法错误;查询中所使用的表/列不存在和试图插入或更新的数据违反了数据库约束。事实上,大多数抛出SQLException的情况是致命的错误。即使对某些SQLException有处理方案,还是要捕获SQLException并查看其属性才能获知问题根源的更多信息。这是因为SQLException被视为处理数据访问所有问题的通用一场。

Spring JDBC提供的数据访问异常体系提供了多个数据访问异常,分别描述了他们抛出时所对应的问题。而且它并没有与特定的持久化方式相关联,这意味着可以使用Spring抛出一致的异常而不用关心所选择的持久化方案。Spring JDBC异常都继承自DataAccessException。DataAccessException是一个非检查型异常,因此不用捕获Srping所抛出的数据访问异常。

模板方法将过程中与特定实现相关的部分委托给接口,而这个接口的不同实现定义了过程中的具体行为。

Spring将数据访问过程中固定的和可变的部分明确划分为两个不同的类:模板(template)和回调(callback)。模板管理过程中固定的部分(书屋控制,管理资源以及处理异常),而回调处理自定义的数据访问代码(应用程序相关的数据访问——语句、绑定参数以及整理结果集)。

Spring提供的数据访问模板,分别适用于不同的持久化机制:

jca.cci.core.CciTemplate  JCA CCI连接

jdbc.core.JdbcTemplate  JDBC连接

jdbc.core.namedparam.NamedParameterJdbcTemplate  支持命名参数的JDBC连接

jdbc.core.simple.SimpleJdbcTemplate  通过Java5简化后的JDBC连接

orm.hibernate3.HibernateTemplate  Hibernate 3.x以上的Session

orm.ibatis.SqlMapClientTemplate  iBatis SqlMap客户端

orm.jdo.JdoTemplate  Java数据对象实现

orm.jpa.JpaTempalte  Java持久化API的实体管理器

Spring提供了在Spring上下文中配置数据源bean的多种方式,包括:通过JDBC驱动程序定义的数据源;通过JNDI查找的数据源和连接池的数据源。也可以使用Apache Commons DBCP、c3p0和BoneCP这些框架来配置Spring的数据源

使用DBCP配置数据源

  基于java的配置

@Bean
public BasicDataSource dataSource(){
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:tcp://localhost/...");
dataSource.setUsernname("username");
dataSource.setPassword("root");
dataSource.setInitialSize(5);
dataSource.setMaxActive(10);
return dataSource
}

  基于xml的配置

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
p:driverClassName="org.h2.Driver"
p:url="jdbc:h2:tcp://localhost/"
p:username="username"
p:password="root"
p:initialSize="5"
p:maxActive="10" />

DBCP BasicDataSource一些常用的池配置属性

initialSize  池启动时创建的连接数量

maxActive  同以时间可以从池中分配的最多连接数,若为0,则表示无限制

madIde  池里不会被释放的最多空闲连接数,若为0,则表示无限制

maxOpenPreparedStatements  在同一时间能够从语句池中分配的预处理语句的最大数量,若为0,则表示无限制

maxWait  在抛出异常之前,池等待连接回收的最大时间,若设置为-1,表示无限等待

minEvictabelIdeTimeMills  连接在池中保持空闲而不被回收的最大时间

minIde  在不创建新连接的情况下,池中保持空闲的最小连接数

poolPreparedStatements  是否对预处理语句进行池管理

在Spring中,通过JDBC驱动定义数据源是最简单的配置方式。Spring提供了三个这样的数据源类供选择:

  DriverManagerDataSource:在每个连接请求时都会返回一个新建的连接。与DBCP的BasicDataSource不同,由DriverManagerDataSource提供的连接并没有进行池化管理

  SimpleDriverDataSource:与DriberManagerDataSource的工作方式类似,但是它直接使用JDBC驱动,来解决在特定环境下的类的加载问题,如OSGi容器

  SingleConnectionDataSource:在每个连接强求时都会返回同一个的连接。尽管SingleConnectionDataSource不是严格意义上的连接池数资源,但可以视其为自由一个连接的池

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:driverClassName="driverClassName"
p:url="jdbc:..."
p:username="username"
p:passord="" />
@Bean
public DataSource dataSource(){
DriverManagerDataSource dataSource =new DriverManagerDataSource();
dataSource.setDriverClassName("driverClassName");
dataSource.setUrl("url");
dataSource.setUsername("username");
dataSource.setPassword("password");
return dataSource;
}

嵌入式数据库(embedded database)作为应用的一部分运行,而不是应用连接的独立数据库服务器。Spring的jdbc命名空间能够简化嵌入式数据库的配置

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/jdbc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http:///www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
http://www.springframework.org/schema/beans
                   http://www.springframework.org/schema/beans/spring-beans.xsd " >
  <jdbc:embedded-datatbase id="dataSource" type="H2">
   <jdbc:script location="" />
   <jdbc:script location="" />
  </jdbc:embedded-database>
</beans>
@Bean
public DataSource dataSource(){
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("classpath:*.sql")
.build();
}

可以将不同的profile配置在不同的数据源中

package cherry.config;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.jndi.JndiObjectFactoryBean; @Configuration
public class DataSourceConfiguration { @Profile("development")
@Bean
public DataSource embeddedDataSource(){
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("classpath:schema.sql")
.addScript("classpath:test-data.sql")
.build();
} @Profile("qa")
@Bean
public DataSource dataSourceForQA(){
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("driverName");
dataSource.setUrl("url");
dataSource.setUsername("username");
dataSource.setPassword("password");
dataSource.setInitialSize(5);
dataSource.setMaxActive(10);
return dataSource;
} @Profile("production")
@Bean
public DataSource dataSource(){
JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
jndiObjectFactoryBean.setJndiName("jdbc/databaseName");
jndiObjectFactoryBean.setResourceRef(true);
jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);
return (DataSource)jndiObjectFactoryBean.getObject();
}
}

Spring JDBC将数据访问的样板代码抽象到模板类之中。Spring为JDBC提供了三个模板类供选择:

  JdbcTemplate: 最基本的Spring JDBC模板,这个模板支持简单的JDBC数据访问功能以及基于索引参数的查询

  NamedParameterJdncTemplate:使用该模板类执行查询时可以将值以命名参数的形式绑定到SQL中,而不是使用简单的索引参数

使用JdbcTemplate只需要为其设置DataSource即可

  @Bean

  public JdbcTemplate jdbcTempalte(DataSource dataSource){

    return new JdbcTemplate(dataSource);

  }

将jdbcTemplate装配到Respository中.JdbcOperations是一个接口,定义了JdbcTemplate所实现的操作

  @Repository

  public class RepositoryImpl implements Respostory{

    private JdbcOperations jdbcOperations;

    @Inject

    public RepositoryImpl(JdbcOperations jdbcOperations){

      this.jdbcOperations = jdbcOperations;

    }

  }

  调用JdbcTemplate.update()方法时会获取连接、创建语句并执行插入SQL;findOne()方法使用了JdbcTemplate的回调;queryForObject()方法从数据库查询,它有三个参数:String(查询数据的sql),rowMapper(从ResultSet中提取数据并构建对象)和可变参数列表(要绑定到查询上的索引参数值)

  命名参数可以赋予SQL中每个参数一个明确的名字,在绑定只到查询语句的时候就通过该名字来引用参数。使用命名参数查询,绑定只的顺序就不重要了。如果查询语句发生了变化导致参数的顺序与之前不一致,也扔不需要修改绑定的代码。

@Bean
public NamedParameterJdbcTemplate jdbcTemplate(DataSource dataSource){
return new NamedParameterJdbcTemplate(dataSource);
} public void addSpitter(Spitter spitter){
private static final String INSER_SPITTER = "insert into spitter(username, password, email) values(:username, :password, :email)";
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("username", spitter.getUsername());
paramMap.put("password", spittler.getPassword());
paramMap.put("email", spitter.getEmail());
jdbcOperations.update(INSER_SPITTER, paramMap);
}

延迟加载(Lazy loading):允许我们在需要的时候获取数据

预先抓取(Eager fetching):借助预先抓取,可以使用一个查询获取完整的关联对象

级联(Cascading):更改数据库中的某些表时会更改其他表

Spring支持多个持久化框架,包括:Hibernate、iBatis、Java数据对象(java data object, JDO)以及Java持久化API(java persistence APT,JPA)。Spring对ORM框架的支持提供了一些附加的服务:支持集成Spring声明式事务;透明的异常处理;线程安全的、轻量级的模板类;DAO支持类和资源管理。

在Spring中集成Hibernate

  声明Hibernate所需的主要接口是org.hibernate.Session。Session接口提供了基本的数据访问功能,如保存、更新、删除以及从数据库加载对象的功能。通过Hibernate的Session接口,应用程序的Repository能够满足所有的持久化需求。获取Hibernate Session对象的标准方式是借助于Hibernate SessionFactory接口的实现类。SessionFactory主要负责Hibernate Session的打开、关闭以及管理。

  Spring3.1+提供了三个SessionFactoryBean供选择:

    org.springframework.orm.hibernate3.LocalSesssionFactoryBean

    org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean

    org.springframework.orm.hibernate4.LocalSessionFactoryBean

  这些Session工厂bean都是Spring FactoryBean接口的实现,它会产生一个HibernateSessionFactory,它能装配进任何SessionFactory类型的属性中。这样就能在Spring应用上下文中,与其他的bean一起配置Hibernate Session工厂。选择SessionFactory取决于使用哪个版本的Hibernate以及使用XML还是使用注解来定义对象-数据库之间的映射关系。

  使用Hibernate3.2-4.0(不包含4.0)并使用XML定义映射,需要使用Spring的org.springframework.orm.hibernate3中的LocalSessionFactoryBean  

@Bean
public LocalSessionFactoryBean sessionFactory(DataSource dataSource){
LocalSessionFactoryBean sfb = new LocalSessionFactoryBean();
sfb.setDataSource(dataSource);
sfb.setMappingResources(new String[]{"Spitter.hbm.xml"});
Properties props = new Properties();
props.setProperty("dialect", "org.hibernate.dialect.H2Dialect");
sfb.setHibernateProperties(props);
return sfb;
}

  使用注解来定义持久化并木有使用Hibernate4,需要使用AnnotationSessionFactoryBean来代替LocalSessionFactoryBean

@Bean
public AnnotationSessionFactoryBean sessionFactory(DataSources dataSource){
AnnotationSessionFactoryBean sfb = new AnnotationSessionFactoryBean();
sfb.setDataSource(dataSource);
sfb.setPackagesToScan(new String[]{"com.spitter.domain"});
Properties props = new Properties();
props.setProperty("dialect", "org.hibernate.dialect.H2Dialect");
sfb.setHibernateProperties(props);
return sfb;
}

  使用Hibernate4应该使用org.springframework.orm.hiberante4中的LocalSessionFactoryBean来生成Session。packagesToScan属性告诉Spring扫描一个或多个包以查找域类,这些类通过注解的方式表明要使用Hibernate进行持久化,这些类可以使用注解包括JPA的@Entity或@MappedSuperclass以及Hibernate的@Entity

@Bean
public LocalSessionFactoryBean sessionFactory(DataSource dataSource){
LocalSesssionFactory sfb = new LocalSessionFactory();
sfb.setDataSource(dataSource);
sfb.setPackagesToScan(new String[]{com.spittr.domain""});
Properties props = new Properties();
props.setProperty("dialect", "org.hibernate.dailect.H2Dialect");
sfg.setHibernateProperties(props);
return sfb;
}

为了不使用模板的Hibernate Repository添加异常转换功能,只需要在Spring应用上下文中添加一个PersistenceExceptionTranslationPostProcessor bean。PersistenceExceptionTranslationPostProcessors是一个bean后置处理器(bean post-processor),它会在所有拥有@Respository注解的类上添加一个通知器(advisor),这样会捕获任何平台相关的异常并以Spring非检查型数据访问异常的形式重新抛出。

@Bean
public BeanPostProcessor persistenceTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}

Spring与JPA

  JPA是基于POJO的持久化机制。

  在Spring中使用JPA的第一不是要在Spring应用上下文中将实体管理工厂(entity manager factory)按照bean的形式来进行配置。

  基于JPA的应用程序需要使用EntityManagerFactory的实现类来获取EntityManager实例。JPA定义了两种类型的实体管理器:

    应用程序管理类型(Application-managed):当应用程序向实体管理器工厂直接请求实体管理器时,工厂会创建一个实体管理器。在这种模式下,程序要负责打开或关闭实体管理器并在事务中对其进行控制。这种方式的实体管理器适合于不运行在Java EE容器中的独立应用程序

    容器管理类型(Container-managed):实体管理器由Java EE创建和管理。应用程序根本不与实体管理器工厂打交道。相反,实体管理器直接通过注入或JNDI来获取。容器负责配置实体管理器工厂。这种类型的实体管理器最适用于Java EE容器,在这种情况下回希望在persistence.xml指定的JPA配置之外保持一些自己对JPA的控制。

  以上两种实体管理器实现了同一个EntityManager接口,区别在于EntityManager的创建和管理方式。应用程序管理类型的EntityManager是由EntityManagerFactory创建的,通过PersistenceProvider的createEntityManagerFactory()方法得到的。容器管理类型的EntityManagerFactory是通过PersistenceProvider的createContainerEntityManagerFactory()方法获得的。

  LocalEntityManagerFactoryBean生成应用程序管理类型的EntityManagerFactory

  LocalContainerEntityManagerFactoryBean生成容器管理类型的EntityManagerFactory

配置应用程序管理类型的JPA

  1.对于应用程序管理类型的实体管理器工厂来说,它绝大部分配置信息来源于一个名为persistence.xml的配置文件,这个必须位于类路径下的META-INF目录下。persistence.xml的作用在于定义一个或多个持久化单元。持久化单元是同一个数据源下的一个或多个持久化类。

<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
<persistence-unit name="spitterPU">
<class>com.domain.Spitter</class>
<class>com.domain.Spittle</class>
<properties>
<property name="toplink.jdbc.driver" value="org.hsqldb.jdbcDriver" />
<property name="toplink.jdbc.url" value="jdbc:hsqldb:hsql://localhost/spitter" />
<property name="toplink.jdbc.user" value="username" />
<property name="toplink.jdbc.password" value="password" />
</properties>
</persistence-unit>
</presistence>

  2.在Spring上下文中声明LocalEntityManagerFactoryBean

@Bean
public LocalEntityManagerFactoryBean entityManagerFactoryBean(){
LocalEntityManagerFactoryBean emfb = new LocalEntityManagerFactoryBean();
emfb.setPesistenceUnitName("spitterPU");
return emfb;
}

  创建应用程序管理类型的EntityManagerFactory都是在persistence.xml中进行的。在应用程序管理的场景下,完全由应用程序本身来负责获取EntityManagerFactory,这是通JPA实现的PersistenceProvider做到的。如果每次请求EntityManagerFactory时都需要定义持久化单元,那么代码会迅速膨胀。通过将其配置在persistence.xml中,JPA就能够在特定的位置查找持久化单元定义。

使用容器管理类型的JPA

  当运行在容器中时,可以使用容器提供的信息来生成EntityManagerFactory。可以将数据源信息配置在Spring应用上下文中,而不是persistence.xml中。

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, JpaVendorAdapter jpaVendorAdapater){
LocalContainerEntityManagerFactoryBean emfb = new LocalContainerEntityManagerFactoryBean();
emfb.setDataSource(dataSource);
emfb.setJpaVendorAdapter(jpaVendorAdapter);
emfb.setPackagesToScan("com.domian");
return emfb;
}

  jpaVendorAdapter属性用于指明所使用的是哪个厂商的JPA。Spring提供了多个JPA厂商适配器:EclipseLinkJpaVendorAdapter;HibernateJpaVendorAdapter;OpenJpaVendorAdapter。

@Bean
public JpaVendorAdapter jpaVendorAdapter(){
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setDatabase("HSQL");
adapter.setShowSql(true);
adapter.setGeneralDdl(false);
adapter.setDatabasePlatform("org.hibernate.dialect.HSQLDialect");
return adapter;
}

  从JNDI获取实体管理工厂

    若将Spring应用程序部署在应用服务器中,EntityManagerFactory可能已经创建好了并且位于JNDI中等待查询使用。在这种情况下,可以使用Spring jee命名空间下的<jee:jndi-lookup>元素来获取对EntityManagerFactory的引用:

  <jee:jndi-lookup id="emf" jndi-name="persistence/spitterPU" />

    通过Java配置来获取EntityManagerFactory

@Bean
public JndiObjectFactoryBean entityManagerFactory(){
JndiObjectFactoryBean jndiObjectFB = new JndiObjectFactoryBean();
jndiObjectFB.setJndiName("jdbc/SpitterDS");
return jndiObjectFB;
}

基于JPA的Respository

@Repository
@Transactional
public class JpaSpitterRepository implements SpitterRespository{
@PersistenceUnit
private EntityManager emf; public void addSpitter(Spittter spitter){
emf.persist(spitter);
} public Spitter getSpitterById(long id){
return emf.find(Spitter.class, id);
} public void saveSpitter(Spitter spitter){
emf.merge(spitter);
} }

  @PersistenceUnit和@PesistenceContext并不是Spring的注解,它们是有JPA规范提供的。我们需要配置Sprong的PersistenceAnnotationBeanPostProcessor。如果使用<context:annotation-config>或<context:component-scan>,则配置元素会自动注册PersistenceAnnotationBeanPostProcessor bean。否则需要在显式注册这个bean

@Bean
public PersistenceAnnotationBeanPostProcessor paPostProcessor(){
return new PersistenceAnnotationBeanPostProcessor();
}

借助Spring Data实现自动化的JPA Repository 

  在xml中配置Spring Data JPA。<jpa:repositories>会扫描它的基础包来查找扩展自Spring Data JPA Respository接口的所有接口。如果发现扩展自Repository的接口,它会自动生成这个接口的实现。

<?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:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/data/jpa
        http://www.springframework.org/schema/data/jpa/sping-jpa-1.0.xsd " >
<jpa:repositories base-package="com.">
</beans>

  使用Java配置则只需要在配置类上添加@EnableJpaRespositories注解

@Configuration
@EnableJpaRespositories(basePackage="")
public class JpaConfiguration{
}
public interface SpitterRepository extends JpaRepository<Spitter, Long>{
  Spitter findByUsername(String username);
  List<Spitter> readByFirstnameOrLastNameAscFirstnameDest(String firstname, String lastname);
  List<Spitter> readByFirstnameIgnoringCaseOrLastnameIgnoresCase(String firstname, String lastname);
}

  实际上,我们并不需要实现findByUsername()。方法签名已经告诉Spring Data JPA足够的信息来创建这个方法的实现了。当创建Repository实现的时候,Spring Data会检查Respository接口的所有方法,解析方法的名称,并基于被持久化的对象来视图推测方法的目的。Repository方法是有一个动词、一个可选的主题、关键词By以及一个断言所组成。在findByUsername()这个样例中,动词是find,断言是Username,主题没有指定,暗含的主题是Spitter。Spring Data允许在方法命中使用四种动词:get、read、find和count。get、read和find都会查询数据并返回对象,而count则会返回匹配对象的数量。对于大部分场景来说,主题会被省略。如果主题的名称以Distinct开头的话,那么在生成查询的时候会确保所返回的结果集中不包含重复记录。断言限制结果集的属性。在断言中,会有一个或多个限制结果的条件。每个条件必须引用一个属性,并且还可以指定一种比较操作。如果省略比较操作符的话,会暗指这是一种相等的比较操作。Spring Data提供了以下几种比较操作符:IsAfter、After、IsGreaterThan、GreaterThan、IsGreaterThanEqual、GreaterThanEqual、IsBefore、Before、IsLessThan、LessThan、IsLessThanEqual、LessThanEqual、IsBetween、Between、IsNull、Null、IsNotNull、NotNull、IsIn、In、IsNotIn、NotIn、IsStartingWith、StartingWith、StartsWith、IsEndingWith、EndingWith、EndsWith、IsContaining、Containing、Contains、IsLike、Like、IsNotLike、NotLike、IsTrue、True、IsFalse、False、Is、Equals、IsNot和Not。处理Stirng类型的属性时,条件中可能还会包含IgnoringCase,IgnoresCase,AllIgnoringCase或AllIgnoresCase。可以在方法名称的结尾处添加OrderBy,实现结果集排序。条件部分是通过And或Or进行分割。

声明自定义查询

  使用@Query方法为Spring Data提供要执行的查询

public interface SpitterRepository extends JpaRepository<Spitter, Long>{
  Spitter findByUsername(String username); @Query("select * from spitter where email like '%gmail.com%'")
List<Spitter> findAllGmailSpitters();
}

Spring Relational Database的更多相关文章

  1. How does a relational database work

    http://blog.jobbole.com/100349/ http://coding-geek.com/how-databases-work/

  2. 关系型数据库 RDS(Relational Database Service),知识点

    资料 网址 官方介绍 https://help.aliyun.com/document_detail/26092.html?spm=5176.2020520104.0.0.2b4b1450yqd1gg ...

  3. Spring Batch Concepts Chapter

    Spring Batch Concepts Chapter The below figure shows two kinds of Spring Batch components:infrastruc ...

  4. SPRING IN ACTION 第4版笔记-第九章Securing web applications-008-使用非关系型数据库时如何验证用户(自定义UserService)

    一. 1.定义接口 Suppose that you need to authenticate against users in a non-relational database suchas Mo ...

  5. SPRING IN ACTION 第4版笔记-第九章Securing web applications-003-把用户数据存在数据库

    一. 1.It’s quite common for user data to be stored in a relational database, accessed via JDBC . To c ...

  6. SPRING IN ACTION 第4版笔记-第九章Securing web applications-002-把用户数据存在memory里(AuthenticationManagerBuilder、 UserDetailsManagerConfigurer.UserDetailsBuilder)

    Spring Security is extremely flexible and is capable of authenticating users against virtually any d ...

  7. Spring Security(三十二):10. Core Services

    Now that we have a high-level overview of the Spring Security architecture and its core classes, let ...

  8. 【Spring Boot&& Spring Cloud系列】单点登录SSO之OAuth2官方开发文档翻译

    Introduction:介绍 This is the user guide for the support for OAuth 2.0. For OAuth 1.0, everything is d ...

  9. Distributed transactions in Spring, with and without XA

    While it's common to use the Java Transaction API and the XA protocol for distributed transactions i ...

随机推荐

  1. java的同步实现

    在java编程中,经常需要用到同步,而同步的实现使用最多的就是synchronized关键字了. synchronized关键字涉及到“锁”的概念,首先先了解一下相关锁的知识. java的内置锁:每个 ...

  2. 牛客练习赛32 A/B/C

    https://ac.nowcoder.com/acm/contest/272/A v<=k时  答案就是k个1 否则贪心的从中间向两边添加1 #include<bits/stdc++.h ...

  3. python中sys.argv[]的使用

    sys.argv[]主要用于程序从外部获取参数.其参数个数可以是多个,组建成一个列表(list). 几个简单示例如下: fun_test.py: #!/usr/bin/env python # -*- ...

  4. zkw线段树模板题

    学了zkw线段树,觉得没什么必要刷专题的吧(切不动啊).. 那先放一个模板题吧(我绝不会和你说搬了一道树状数组模板题的!!!) 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某一个数加 ...

  5. Vuejs选项卡案例

    css .active { color: red; border-bottom: 1px solid red; } ul li { padding: 0 15px; float: left; list ...

  6. js正则表达式 replace替换url的参数

    /* 定义替换对象键值 */var setReferArgs = function(){    var referArgs = new Object();    referArgs['#userID\ ...

  7. mysql索引简单分析

    索引对查询的速度有着至关重要的影响,理解索引也是进行数据库性能调优的起点.考虑如下情况,假设数据库中一个表有10^6条记录,DBMS的页面大小为4K,并存储100条记录.如果没有索引,查询将对整个表进 ...

  8. 返回JSON格式(二十五)

    在上述例子中,通过@ControllerAdvice统一定义不同Exception映射到不同错误处理页面.而当我们要实现RESTful API时,返回的错误是JSON格式的数据,而不是HTML页面,这 ...

  9. js 鼠标滚动 禁用 启用

    function disabledMouseWheel() { var div = document.getElementById('divid'); if (div.addEventListener ...

  10. linux下正则表达式学习

    下表包含了元字符的完整列表以及它们在正则表达式上下文中的行为: 字符 描述 \ 将下一个字符标记为一个特殊字符.或一个原义字符.或一个 向后引用.或一个八进制转义符.例如,'n' 匹配字符 " ...