SpringBoot data access

1, Introduction

   for the data access layer, whether SQL or NOSQL, SpringBoot adopts the method of integrating Spring Data for unified processing by default, adding a large number of automatic configurations. xxxTemplate and xxxRepository are introduced to simplify the operation of data access layer.

<dependency>  <!-- mysql-connector-java Dependency is required (when used) Mysql Database) -->
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.18</version>
</dependency>

2, Using JDBC

1. Add dependency

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

2. Use

application.yml (mysql higher version must take the following url parameters, specify time zone, character, SSL)

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false
    username: xxxxxx
    password: ******

Test code

import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestDatasource {
	
	@Autowired
	DataSource datasource;
	
	@Test
	public void contextLoads() throws SQLException {
		System.out.println("Data source class"+datasource.getClass());
        //com.zaxxer.hikari.HikariDataSource SpringBoot2 default data source
        //org.apache.tomcat.jdbc.pool.DataSource SpringBoot1.5 default data source
		Connection connection = datasource.getConnection();
		System.out.println(connection);
		connection.close();
	}
}

3. Common functions

Core package: org.org springframework. boot. autoconfigure. jdbc

3.1 selecting data sources

to configurevalue
spring.datasource.typeorg.apache.tomcat.jdbc.pool.DataSource
com.zaxxer.hikari.HikariDataSource (default)
org.apache.commons.dbcp2.BasicDataSource

3.2 execute sql file at project startup

spring:
  datasource:
  	platform: mysql  # Designated platform
    initialization-mode: always  #Auto execute schema - * sql data-*. SQL, no need to
    schema:
    - classpath:sql/schema-jk.sql  # Custom sql location

  Description:

  1. Default sql storage location: classpath
  2. SQL: schema. Is executed by default sql,schema-all.sql,data.sql,data-all.sql
  3. Customizable sql location and name
  4. platform can be specified:

3.3 database operation

Core class: JdbcTemplate

@Autowired
JdbcTemplate jdbcTemplate;

@ResponseBody
@GetMapping("/jdbcSelect")
public List<Map<String, Object>> jdbcSelect() {
    List<Map<String, Object>> queryForList = jdbcTemplate.queryForList("select * from t_user");
    return queryForList;
}

3, Data source Druid

1. Switch data source

Add pom dependency:

<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.21</version>
</dependency>

Modify data source: application yml

spring:
	datasource:
		type: com.alibaba.druid.pool.DruidDataSource

2. Add druid configuration

spring:
  datasource:
#   Other configurations of data source
    initialSize: 5  #Number of initial connections
    minIdle: 5		#Minimum idle
    maxActive: 20	#maximum connection
    maxWait: 60000	#Maximum waiting time ms
    timeBetweenEvictionRunsMillis: 60000 #Running idle collector interval ms
    minEvictableIdleTimeMillis: 300000	#The connection in the pool can be recycled after being idle for 5m
    validationQuery: SELECT 1 FROM DUAL #Verify the sql used
    testWhileIdle: true		#Indicates whether the connection is verified by the idle connection collector (if any) If the test fails, the connection will be removed from the pool  
    testOnBorrow: false		#Whether to verify the availability when getting an instance
    testOnReturn: false		#Whether to validate in advance when return ing to pool
    poolPreparedStatements: false #Cache cursor
#   Configure the filters for monitoring statistics interception. After removal, the sql in the monitoring interface cannot be counted, 'wall' is used for firewall  
    filters: stat,wall,slf4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true  
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

java code

@Configuration
public class ApplicationConfiguration {
	
	@Bean
	@ConfigurationProperties(prefix = "spring.datasource")
	public DruidDataSource getDataSource() {
		return new DruidDataSource();
	}
}

druid configuration resolution

to configureexplain
initialSizeNumber of initial connections
minIdleMinimum idle number
maxActivemaximum connection
maxWaitConfigure the timeout time for getting connections
timeBetweenEvictionRunsMillisHow often is the configuration interval detected? Idle connections that need to be closed are detected in milliseconds
minEvictableIdleTimeMillisConfigure the minimum lifetime of a connection in the pool, in milliseconds
validationQueryVerify the sql used
testWhileIdleIndicates whether the connection is verified by the idle connection collector (if any) If the detection fails, the connection will be removed from the pool.
testOnBorrowWhether to verify the availability when getting an instance
testOnReturnWhether to validate in advance when return ing to pool
poolPreparedStatementsOpen PSCache
maxPoolPreparedStatementPerConnectionSizeSpecifies the size of the PSCache on each connection
filtersConfigure the filters for monitoring statistics interception. After removing the filters, the sql in the monitoring interface cannot be counted, 'wall' is used for firewall
connectionPropertiesOpen the mergeSql function through the connectProperties property; Slow SQL record
useGlobalDataSourceStatMerge monitoring data of multiple DruidDataSource

3. Configuration monitoring

//Configure Druid monitoring
//1. Configure the Servlet in the management background 
@Bean
public ServletRegistrationBean<StatViewServlet> statViewServlet(){
    ServletRegistrationBean<StatViewServlet> servletRegistrationBean = new ServletRegistrationBean<StatViewServlet>(new StatViewServlet(), "/druid/*");
    /* The value can be stored in the initial servlet, and the key is fixed. Class ResourceServlet can be viewed */
    Map<String, String> initParameters = new HashMap<>();
    initParameters.put("loginUsername", "jinkun");
    initParameters.put("loginPassword", "123456");
    initParameters.put("allow","");//Allow all by default
    initParameters.put("deny","192.168.56.1"); //Point to the machine that does not have access, and the value is ip address
    servletRegistrationBean.setInitParameters(initParameters);
    return servletRegistrationBean;
}

//2. Configure a web monitoring Filter
@Bean
public FilterRegistrationBean<WebStatFilter> webStatFilter(){
    FilterRegistrationBean<WebStatFilter> filterRegistrationBean = new FilterRegistrationBean<>();
    filterRegistrationBean.setFilter(new WebStatFilter());
    filterRegistrationBean.setUrlPatterns(Arrays.asList("/*")); //Filter all
    Map<String, String> initParameters = new HashMap<>();
    initParameters.put("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"); //Exclude unfiltered	
    filterRegistrationBean.setInitParameters(initParameters);
    return filterRegistrationBean;
}

Monitoring page:

4, Integrate Mybatis

Help documentation: https://mybatis.org/mybatis-3/zh/

1. Introduce dependency

  mybatis is not an official dependency of Spring Boot, so you need to add a version number.

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.1</version>
</dependency>

2. Annotated version

2.1 notes

annotationexplain
@MapperIt is marked in front of the class to indicate that this class is a class that operates the database
@MapperScan@Mapper annotates each class and @ MapperScan(value = "package name") is placed before the startup class, so the classes under this package do not need @ mapper annotation.
@InsertInsert statement
@SelectQuery statement
@UpdateUPDATE statement
@DeleteDelete statement
@ParamMethod Parameter annotation, when the field name in the database is inconsistent with the field name of java bean
@Results and @ ResultConvert the values queried in the database into specific fields
#{} and ${}#It is used to preprocess SQL and $is used to splice SQL1
@InsertProviderDynamically generate SQL, type: the class that dynamically generates SQL, method: the specific method name in the class
@SelectProviderDynamically generate SQL, type: the class that dynamically generates SQL, method: the specific method name in the class
@UpdateProviderDynamically generate SQL, type: the class that dynamically generates SQL, method: the specific method name in the class
@DeleteProviderDynamically generate SQL, type: the class that dynamically generates SQL, method: the specific method name in the class
@OptionsuseGeneratedKeys=true ; keyProperty = "id" select whether to auto increment and auto increment columns
xml configuration fileCore Bean: org apache. ibatis. session. Configuration. ConfigurationCustomizer

@Insert, @ Select, @ Update, @ Delete, @ Param examples

@Select("SELECT * FROM users WHERE user_sex = #{user_sex}")
List<User> getListByUserSex(@Param("user_sex") String userSex); 

@Results and @ Result examples:

@Select("SELECT * FROM users")
@Results({
    @Result(property = "userSex",  column = "user_sex", javaType = UserSexEnum.class),
    @Result(property = "nickName", column = "nick_name")
})
List<UserEntity> getAll();

2.2 sql Statement Builder

  sql Statement Builder is aimed at the use of dynamic sql: if, choose, foreach and trim in annotation mode

   the sql Statement Builder will create a method to return sql and use it in combination with @ xxxProvider.

methodexplain
SELECT(String)
SELECT(String ...)
Start or insert into the SELECT clause. It can be called multiple times, and the parameter will be added to the SELECT clause. Parameters usually use comma separated column names and alias lists, but they can also be any type accepted by the database driver.
SELECT_DISTINCT(String) SELECT_DISTINCT(String...)Start or insert into the SELECT clause, or insert the DISTINCT keyword into the generated query statement. It can be called multiple times, and the parameter will be added to the SELECT clause. Parameters usually use comma separated column names and alias lists, but they can also be any type accepted by the database driver.
FROM(String)
FROM(String...)
Start or insert into the FROM clause. Can be called multiple times, and parameters are added to the FROM clause. Parameters are usually table names or aliases, or any type accepted by the database driver.
JOIN(String)
JOIN(String...)
INNER_JOIN(String)
INNER_JOIN(String...)
LEFT_OUTER_JOIN(String) LEFT_OUTER_JOIN(String...) RIGHT_OUTER_JOIN(String) RIGHT_OUTER_JOIN(String...)
Add a new join clause of the appropriate type based on the called method. The parameter can contain a standard join composed of column names and join on conditions.
WHERE(String)
WHERE(String...)
Insert a new WHERE clause condition, linked by AND. It can be called many times, AND the new condition is linked by AND each time. Use OR() to separate OR.
OR()Use OR to separate the current WHERE clause conditions. Can be called multiple times, but call multiple times in a row OR generate unstable SQL.
AND()Use AND to separate the current WHERE clause condition. Can be called multiple times, but call multiple times in a row or generate unstable SQL. Because both WHERE AND HAVING will automatically link AND, this is a very rare method, which is only used for integrity.
GROUP_BY(String)
GROUP_BY(String...)
Insert a new GROUP BY clause element, joined by commas. Can be called multiple times, each time with a comma connecting the new condition.
HAVING(String)
HAVING(String...)
Insert a new HAVING clause condition. Connected by AND. Can be called multiple times, each time by AND to connect the new condition. Use OR() to separate OR
ORDER_BY(String)
ORDER_BY(String...)
Insert new ORDER BY clause elements, joined by commas. Can be called multiple times, each time a new condition is concatenated by a comma.
LIMIT(String)
LIMIT(int)
This method is valid when used with SELECT(), UPDATE(), and DELETE(). This method is designed to be used with OFFSET() when using SELECT(). (provided from 3.5.2)
OFFSET(String)
OFFSET(long)
This method is valid when used with SELECT(). This method is used with LIMIT(). (provided from 3.5.2)
OFFSET_ROWS(String)
OFFSET_ROWS(long)
Append an OFFSET n ROWS clause. This method is valid when used with SELECT(). This method is designed with fetch_ FIRST_ ROWS_ Use with only(). (provided from 3.5.2)
FETCH_FIRST_ROWS_ONLY(String) FETCH_FIRST_ROWS_ONLY(int)Append a FETCH FIRST n ROWS ONLY clause. This method is valid when used with SELECT(). This method is designed to work with offset_ Use with rows(). (provided from 3.5.2)
DELETE_FROM(String)Start a delete statement and specify the table name from which you want to delete. Usually it will be followed by WHERE statement!
INSERT_INTO(String)Start an insert statement and specify the name of the table into which you want to insert data. One or more values () or into will follow_ COLUMNS() and INTO_ VALUES().
SET(String)
SET(String...)
Insert the update statement into the "set" list
UPDATE(String)Start an update statement and specify the indication that needs to be updated. It will be followed by one or more sets (), and usually there will be a WHERE().
VALUES(String, String)Insert into the insert statement. The first parameter is the name of the column to be inserted, and the second parameter is the value of the column.
INTO_COLUMNS(String...)Append a column phrase to the insert statement. This should be called together to_ VALUES ().
INTO_VALUES(String...)Append a value phrase to the insert statement. This should be called with_ COLUMNS ().
ADD_ROW()Add new rows for bulk insert. (provided from 3.5.2)

@InsertProvider, @ SelectProvider, @ UpdateProvider, @ DeleteProvider examples

//In interface
@SelectProvider(type=DepartmentMapperClass.class ,method = "sql")
public Department getDeptbyId(Integer id);
//In class
public String sql() {
    return "select * from department where id = #{id}";
}

sql Statement Builder example: don't care about accidental and, where

String sql = "SELECT P.ID, P.USERNAME, P.PASSWORD, P.FULL_NAME, "
"P.LAST_NAME,P.CREATED_ON, P.UPDATED_ON " +
"FROM PERSON P, ACCOUNT A " +
"INNER JOIN DEPARTMENT D on D.ID = P.DEPARTMENT_ID " +
"INNER JOIN COMPANY C on D.COMPANY_ID = C.ID " +
"WHERE (P.ID = A.ID AND P.FIRST_NAME like ?) " +
"OR (P.LAST_NAME like ?) " +
"GROUP BY P.ID " +
"HAVING (P.LAST_NAME like ?) " +
"OR (P.FIRST_NAME like ?) " +
"ORDER BY P.ID, P.FULL_NAME";

amount to:

private String selectPersonSql() {
  return new SQL() {{
    SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FULL_NAME");
    SELECT("P.LAST_NAME, P.CREATED_ON, P.UPDATED_ON");
    FROM("PERSON P");
    FROM("ACCOUNT A");
    INNER_JOIN("DEPARTMENT D on D.ID = P.DEPARTMENT_ID");
    INNER_JOIN("COMPANY C on D.COMPANY_ID = C.ID");
    WHERE("P.ID = A.ID");
    WHERE("P.FIRST_NAME like ?");
    OR();
    WHERE("P.LAST_NAME like ?");
    GROUP_BY("P.ID");
    HAVING("P.LAST_NAME like ?");
    OR();
    HAVING("P.FIRST_NAME like ?");
    ORDER_BY("P.ID");
    ORDER_BY("P.FULL_NAME");
  }}.toString();
}

2.3 xml version

Mybatis global configuration:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<!-- Global configuration: https://mybatis.org/mybatis-3/zh/configuration.html -->
</configuration>

MySQL configuration sql

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.mybatis.example.BlogMapper">
  <select id="selectBlog" resultType="Blog" parameterType="int">
    select * from Blog where id = #{id}
  </select>
  <!-- Related documents: https://mybatis.org/mybatis-3/zh/sqlmap-xml.html -->
</mapper>

Write relevant interface classes:

namespace: package name Class name

id: method name, resultType: return type, parameterType: parameter type

application.yml

mybatis:
  config-location: classpath:mybatis/mybatis-config.xml  #Global profile
  mapper-locations:			#xml Mapping File
  - classpath:mybatis/mapper/*.xml

5, SpringData JPA

1. Introduction

  the purpose of Spring Data project is to simplify the construction of data access technology based on Spring framework applications. Including non relational database, map reduce framework, cloud data service, etc; It also includes access to relational databases.

   spring data provides us with a unified API to operate the data access layer; This is mainly implemented by the Spring Data Commons project. Spring Data Commons allows us to use relational or non relational data access technologies based on the unified standards provided by spring. The standard includes CRUD, paging and sorting operations.

2. Advantages

  • Unified Repository interface
org.springframework.data.repository.Repository<T, ID>  //Unified interface
org.springframework.data.repository.CrudRepository<T, ID> //CRUD based operation
org.springframework.data.repository.PagingAndSortingRepository<T, ID> //Paging and sorting, also CRUD
org.springframework.data.jpa.repository.JpaRepository<T, ID> //There are CRUD, paging and sorting
  • Provide data access template class xxtemplate; Such as MongoTemplate and RedisTemplate*
  • The core is that you can complete the operation without writing sql.

3. Introduce dependency

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

application.yml

spring:
  jpa:
    hibernate:
      ddl-auto: update #Update or create data table structure
    show-sql: true  #The console displays sql

4. Build entity classes (JavaBean s)

This class automatically creates the table corresponding to this entity class in the database through some annotations.

annotationexplain
@EntityBefore labeling a class, indicate that the class should be mapped to the database
@TableClass, attribute: name: points to the table
@ColumnAttribute annotation, attribute: columnDefinition: database type to which the field belongs, name: column name
lenght: Varchar length, precision=8, scale=2: floating point precision, range,
Whether unique=true, nullable=false is unique and empty.
@TemporalCalendar mapping date; Date mapping time; Date mapping timestamp
@TransientDo not save properties to the database
@IdPrimary key column
@GeneratedValueAutomatic generation, strategy: generation strategy: IDENTITY
@SequenceGeneratorCreate a sequence for use with @ GeneratedValue
@LobJava types are byte[] Byte [] and Serializable types that map to blobs, while char[] Character [] and String objects map to clobs
@BasicAttribute: fetch: value lazy / Eagle delayed or eager loading; For @ Lob
Help documentationhttps://www.w3cschool.cn/java/jpa-manytomany-map.html

Example:

Date type: supported time types include: Java sql. Date,java.sql.Time,java.sql.Timestamp,java.util.Date,java.util.Calendar.

@Column(name = "START_DATE", columnDefinition = "DATE DEFAULT CURRENT_DATE")
private java.sql.Date startDate;

@Temporal

@Temporal(TemporalType.DATE) //Calendar mapping date
private java.util.Calendar dob;
@Temporal(TemporalType.TIME) //Date mapping time
private java.util.Date dob;
@Temporal(TemporalType.TIMESTAMP) //Date mapping timestamp
private java.util.Date dob;

@GeneratedValue

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@SequenceGenerator

@SequenceGenerator(name="Emp_Gen", sequenceName="Emp_Seq")
@Id @GeneratedValue(generator="Emp_Gen")
private int id;

5. Data operation

  write interface to inherit jparepository < entity class, primary key >

There are three ways to write sql in the interface: 1. Method in JpaRepository; 2. Custom method; 3. @ Query annotation

  1. For the JpaRepository method, please check the source code
  2. Custom method - SpringData JPA rule
key wordsampleJPQL fragment
AndfindByLastnameAndFirstname... where x.lastname = ?1 and x.firstname = ?2
OrfindByLastnameOrFirstname... where x.lastname = ?1 or x.firstname = ?2
Is, EqualsfindByFirstname,findByFirstnameIs,findByFirstnameEquals... where x.firstname = ?1
BetweenfindByStartDateBetween... where x.startDate between ?1 and ?2
LessThanfindByAgeLessThan... where x.age < ?1
LessThanEqualfindByAgeLessThanEqual... where x.age <= ?1
GreaterThanfindByAgeGreaterThan... where x.age > ?1
GreaterThanEqualfindByAgeGreaterThanEqual... where x.age >= ?1
AfterfindByStartDateAfter... where x.startDate > ?1
BeforefindByStartDateBefore... where x.startDate < ?1
IsNull, NullfindByAge(Is)Null... where x.age is null
IsNotNull, NotNullfindByAge(Is)NotNull... where x.age not null
LikefindByFirstnameLike... where x.firstname like ?1
NotLikefindByFirstnameNotLike... where x.firstname not like ?1
StartingWithfindByFirstnameStartingWith… where x.firstname like ?1 (parameter attached%)
EndingWithfindByFirstnameEndingWith… where x.firstname like ?1 (prefix% for parameters)
ContainingfindByFirstnameContaining… where x.firstname like ?1 (parameter bound in%)
OrderByfindByAgeOrderByLastnameDesc... where x.age = ?1 order by x.lastname desc
NotfindByLastnameNot... where x.lastname <> ?1
InfindByAgeIn(Collection ages)... where x.age in ?1
NotInfindByAgeNotIn(Collection ages)... where x.age not in ?1
TruefindByActiveTrue()... where x.active = true
FalsefindByActiveFalse()... where x.active = false
IgnoreCasefindByFirstnameIgnoreCase... where UPPER(x.firstame) = UPPER(?1)
  1. @Query annotation
//@Modifying
@Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
//? 1 ? 2 indicates the position of the parameter. The attribute nativeQuery=true/false in @ Query indicates whether the field in the statement is a field of data (true) or an attribute in the entity class
//The modification statement needs to be annotated with @ Modifying
  1. specification query to deal with dynamic sql construction. Implement interface jpaspecification executor

The method of JpaSpecificationExecutor needs to pass in the Specification object to build dynamic sql. The core method is as follows:

public interface Specification<T> extends Serializable{
    @Nullable
	Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);
}
//root: used to get database fields
//query: used to combine conditions and return the Specification object
//criteriaBuilder: used to build relationships among multiple conditions: like, and, or

Example:

@RestController
public class JpaController {
	@Autowired
	UserMapper um;
	
	@GetMapping("/user/{id}")
	public User getUserbyId(@PathVariable Long id) {
		return um.getOne(id);
	}
}
//dao layer
public interface UserMapper extends JpaRepository<User, Long>{

}
//Entity class
@Entity
@Table(name ="user")
@JsonIgnoreProperties(value = { "hibernateLazyInitializer", "handler" }) //When a field in an entity class is null, an error will be reported when converting to JSON. This annotation can be added to solve it.
public class User {

ate(Root root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);
}
//root: used to get database fields
//query: used to combine conditions and return the Specification object
//criteriaBuilder: used to build relationships among multiple conditions: like, and, or

```java
@RestController
public class JpaController {
	@Autowired
	UserMapper um;
	
	@GetMapping("/user/{id}")
	public User getUserbyId(@PathVariable Long id) {
		return um.getOne(id);
	}
}
//dao layer
public interface UserMapper extends JpaRepository<User, Long>{

}
//Entity class
@Entity
@Table(name ="user")
@JsonIgnoreProperties(value = { "hibernateLazyInitializer", "handler" }) //When a field in an entity class is null, an error will be reported when converting to JSON. This annotation can be added to solve it.
public class User {

Keywords: Spring Boot

Added by parthatel on Sat, 12 Feb 2022 06:28:03 +0200