Spring Template-based JDBC usage

JDBC embarrassment

      JDBC is a standard API for relational databases on the Java platform, and its success is obvious to all. Almost all data access of the Java platform uses JDBC directly or indirectly. It is the cornerstone of the entire Java platform for data access to relational databases. As a standard, JDBC is undoubtedly successful. But to say that JDBC is also popular in actual use, it is not the case. The JDBC standard is mainly for lower-level database operations. During the design process, the JDBC standard is closer to the lower level to provide as many functional features as possible. From this perspective, the design of the JDBC API is understandable. However, API design that is too close to the bottom layer is not necessarily a good thing for developers to use. Even if a simple query or update is performed, developers must write a lot of similar code according to the rules of the API. In addition to the use of APIs, when formulating data access exception handling, the JDBC specification only includes a single SQLException type to include all data access exceptions, and declares SQLException as a checked exception, and SQLException does not use subclassing specific exceptions to further Abstract different data access exceptions, but use ErrorCode to distinguish between different exceptions that occur during data access. However, the JDBC specification leaves the ErrorCode specification to each database provider, which leads to different ErrorCodes for databases provided by different providers. 

       In view of the error-prone and cumbersome use of the JDBC API during use, and the lack of SQLException's ability to handle data access exceptions yet to be improved, the Spring framework provides a set of framework classes for JDBC usage to improve the JDBC API usage process The various inconveniences or even unreasonable in the help us to further improve the development efficiency of using JDBC for data access during the development process. 

The birth of JDBCTemplate

       In order to solve the embarrassing situation of the JDBC API in actual use, the Spring framework proposed org.springframework.jdbc.core.JdbcTemplate as the Helper class for data access. JdbcTemplate is the basis of all JDBC API best practices provided by the entire Spring data abstraction layer. Other more convenient Helper classes and higher-level abstractions in the framework are all built on JdbcTemplate. Understanding JdbcTemplate understands the Spring framework JDBC API The core of best practice. In a nutshell, JdbcTemplate focuses on the following two things:

  • Encapsulate all JDBC-based data access codes and use the JDBC API in a unified format and specification. All JDBC-based data access requirements are now carried out through JdbcTemplate, thus avoiding the cumbersome and error-prone data access code based on JDBC API scattered throughout the system.
  • The exception information provided by SQLException is uniformly translated within the framework, and JDBC-based data access exceptions are incorporated into Spring's own exception hierarchy system, which unifies the definition of data interfaces and simplifies the handling of data access exceptions by client code.

Let's take a look at the implementation structure diagram of JdbcTemplate as follows:

The org.springframework.jdbc.core.JdbcOperations interface definition defines the set of JDBC operations that JdbcTemplate can use. The operation statement provided by this interface covers everything from query to update, and the direct parent class of JdbcTemplate is org.springframework.jdbc. support.JdbcAccessor, which is an abstract class, mainly provides some common properties for subclasses as follows: 

DataSource。 

javax.sql.DataSource is an interface definition introduced after JDBC2.0, used to replace the method of creating a database connection based on java.sql.DriverManager. The role of DataSource can be seen as a JDBC connection factory (ConnectionFactory), the specific implementation can introduce a buffer pool for database connections and distributed transaction support. Therefore, the Spring data access layer's access to database resources is all based on the standard interface of javax.sql.DataSource. Through the superclass JdbcAccessor, JdbcTemplate is naturally based on this.

1) Types of DataSource 

  •  Simple DataSource implementation class

org.springframework.jdbc.datasource.DriverManagerDataSource

  • DataSource implementation class with connection buffer pool

org.apache.commons.dbcp.BasicDataSource

com.mchange.v2.c3p0.ComboPooledDataSource

com.alibaba.druid.pool.DruidDataSource

  • DataDource implementation class supporting distributed transactions

 javax.sql.XADataSource

2). DataSource access method

  •  Local DataSource access

 Code way:

BasicDataSource dataSourc = new BasicDataSource();
dataSource.setDrierClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost/mysql?useUnicode=true");
dataSource.setUsername("xxx");
dataSource.setPassword("password");

 IoC injection xml:

<bean id="dataSource"
		class="org.apache.commons.dbcp.BasicDataSource"
		destroy-method="close">
		<property name="driverClassName"
			value="org.gjt.mm.mysql.Driver">
		</property>
		<property name="url"
			value="jdbc:mysql://221.11.45.91:3306/new_film?autoReconnect=true&amp;useUnicode=true&amp;characterEncoding=UTF8">
		</property>
		<property name="username" value="root"></property>
		<property name="password" value="root"></property>
		<property name="maxActive" value="25" />
		<property name="maxWait" value="25" />
		<!-- 如果设为true则tomcat自动检查恢复重新利用,没有正常关闭的Connection.(默认是false) -->
		<property name="removeAbandoned" value="true"></property>
		<!-- 设定连接在多少秒内被认为是放弃的连接,即可进行恢复利用 -->
		<property name="removeAbandonedTimeout" value="10"></property>
		<!-- 输出回收的日志,可以详细打印出异常从而发现是在那里发生了泄漏 -->
		<property name="logAbandoned" value="true"></property>
</bean>
  • Remote DataSource access

 In the Tomcat configuration file server.xml (apache-tomcat-9.0.8 \ conf)

<Resource 
        name="jdbc/Sybase_claims"
        auth="Container" 
        type="javax.sql.DataSource"
        maxActive="100" 
        maxIdle="30" 
        maxWait="10000"
        username="test" 
        password="test"
        driverClassName="com.sybase.jdbc4.jdbc.SybDriver"
        url="jdbc:sybase:Tds:127.0.0.1:4101?ServiceName=db_claims"/>

 Ioc injection

<bean id="dataSource"
		class="org.springframework.jndi.JndiObjectFactoryBean"
		destroy-method="close">
		<property name="jndiName" value="java:comp/env/jdbc/Sybase_claims" />
</bean>

SQLExceptionTranslator。 

JdbcTemplate directly operates the JDBC API, so it needs to catch and handle SQLException that may occur during this period. The purpose of the processing is to translate SQLException to Spring's data access exception hierarchy to unify the handling of data access exceptions. JdbcTemplate translates SQLException to Spring data access exception hierarchy. This part of the work is transferred to the org.springframework.jdbc.support.SQLExceptionTranslator interface. This interface has two main implementation classes, as shown below:

SQLErrorCodeSQLExceptionTranslator will perform exception translation based on the ErrorCode returned by SQLException. Usually, the analysis based on the ErrorCode provided by each database provider is much more accurate than the SQLState-based approach. By default, JdbcTemplate uses SQLErrorCodeSQLExceptionTranslator to translate SQLException. Only when errorCode cannot provide enough information, will turn to SQLStateSQLExceptionTranslator. SQLStateSQLExceptionTranslator performs exception translation based on the information returned by SQLException.getSQLState (). Although the method based on SQLState should be the most versatile in theory (because SQLState requires compliance with the XOPEN SQLstate specification or SQL99 specification), there are differences in the implementation of various database vendors. More often, it is based on ErrorCode.

 The process of SQLErrorCodeSQLExceptionTranslator for exception translation is roughly as follows:

1). SQLStateSQLExceptionTranslator defines a custom exception translation method: 

DataAccessException customTranslate(String task,String sql,SQLException sqlEx) 

The program will first check whether the custom exception translation method can translate the current incoming SQLException. If it can directly return the translated DataAccessException type; if it returns null, it means that the current method cannot translate the incoming SQLException. The process goes to the next step, seeking other ways to translate.

2). If the program runs after Java 6, SQLStateSQLExceptionTranslator will try to make SQLExceptionSuclassTranslator to translate the exception. For versions prior to Java 6, this step is not processed.

3). Use SQLErrorCodes loaded by org.springframework.jdbc.support.SQLErrorCodesFactory for exception translation. The process of loading SQLErrorCodes by SQLErrorCodesFactory is:

  • Load the configuration files that record the error codes of each database provider under the path org / springframework / jdbc / support / sql-error-codes.xml in the Spring release jar package, and provide the corresponding SQLErrorCodes.
  • If a configuration file named sql-error-codes.xml exists under the root path of the Classpath of the current application, the content of the file is loaded, and the default ErrorCode definition is overwritten.

4). If the error translation based on ErrorCode is still unclear, SQLStateSQLExceptionTranslator will turn to SQLStateSQLExceptionTranslator, and finally use SQLState-based method to translate SQLException to Spring data access exception system.

The exception can be customized through the following two steps:

  • Extend SQLStateSQLExceptionTranslator to implement its subclass, overriding customTranslate method
  • Provide sql-error-codes.xml custom configuration, place the configuration file named sql-error-codes.xml in the root path of Classpath, the format must be the same as the default org / springframework / jdbc / support / sql-error-codes The .xml file format is the same

Other types of JDBCTemplate 

NamedParameterJdbcTemplate

Usually execute SQL contains? When using placeholders, PreparedStatement and CallableStatement are generally used. If it is the following SQL statement, use the named parameter symbol as a placeholder statement

select * from user where id=:id 

We can use NamedParameterJdbcTemplate to execute, use it, not to provide parameter values ​​for the corresponding placeholders in the form of Object [] array, but through the org.springframework.jdbc.core.namedparam.SqlParameterSource interface, which defines two implementations The classes are org.springframework.jdbc.core.namedparam.MapSqlParameterSource and org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource. 

  • MapSqlParameterSource implementation, the key value must be consistent with the sql attribute name
DataSource dataSource = ...;
final String sql = "select count(1) from images where filename=:filename and desc=:desc"; 
NamedParameterJdbcTemplate npJdbcTemplate = new NamedParameterJdbcTemplate(datasource);
SqlParameterSource parameterSource = new MapSqlParameterSource("filename","image.jpg");
parameterSource.addValue("desc","this is a pictrue");
npJdbcTemplate.queryForInt(sql,parameterSource);
  • The implementation of BeanPropertySqlParameterSource must be the same as the name of the pojo property and sql property
public class Image{
    private int id;
    private String filename;
    private byte[] entity;
    private String desc;

    //对应的setter和getter方法
}
DataSource dataSource = ...;
final String sql = "select count(1) from images where filename=:filename and desc=:desc"; 
NamedParameterJdbcTemplate npJdbcTemplate = new NamedParameterJdbcTemplate(datasource);
Image image = new Image();
image.setFilename("","");
image.setDesc("","");
SqlParameterSource parameterSource = new BeanPropertySqlParameterSource(image);
npJdbcTemplate.queryForInt(sql,parameterSource);

 SimpleJdbcTemplate 

SimpleJdbcTemplate integrates the functions of JdbcTemplate and namedParameterJdbcTemplate into one, and adds dynamic parameter (varargs), auto unboxing (autoboxing) and generic (generic) support introduced after Java 5 on these two. 

DataSource dataSource = ...;
String sql = "select * from images where filename=:filename and desc=:desc"; 
SimpleJdbcTemplate simpleJdbcTemplate = new SimpleJdbcTemplate(datasource);
final LobHandler lobHandler = new DefaultLobHandler();
ParameterizedRowMapper<Imager> rowmapper = new ParameterizedRowMapper<Imager>(){
    public Imager mapRow(ResultSet rs,int row)throws SQLException{
        Imager imager = new Imager();
        imager.setFilename(rs.getInt(1));
        imager.setFilename(rs.getString(2));
        imager.setEntity(lobHandler.getBlobAsBytes(rs,3));
        imager.setDesc(rs.getString(4));
        return imager;
    }
}
Imager imager = simpleJdbcTemplate.queryForObject(sql,rowMapper,"","this is a pictrue");

Use DataSourceUtils for Connection Management

Connection conn = DataSourceUtils.getConnection(datasource); 

DAO layer encapsulating JDBC API using JdbcDaoSupport 

    Spring's JdbcDaoSupport refactored the DAO implementation class, encapsulating all DataSource and JdbcTemplate. Therefore, DAO directly inherits JdbcDaoSupport inherits DataSource and JdbcTemplate.

Published 203 original articles · won praise 6 · views 4498

Guess you like

Origin blog.csdn.net/weixin_42073629/article/details/105314394