SpringInAction笔记(十)——通过Spring和JDBC征服数据库

10.1 Spring的数据访问哲学
     为了避免应用与特定的数据访问策略耦合在一起,编写良好的 Repository应该以接口的方式暴露功能。图10.1展现了设计数据访问层 的合理方式。


SpringInAction笔记(十)——通过Spring和JDBC征服数据库 - 叶主任 - 叶主任的博客
       服务对象通过接口来访问Repository。这样做会有几个好处。第一,它使得服务对象易于测试,因为它们不再与特定的数据访问实现绑定在一起。实际上,你可以为这些数据访问接口创建mock实现,这样无需连接数据库就能测试服务对象,而且会显著提升单元测 试的效率并排除因数据不一致所造成的测试失败。
       此外,数据访问层是以持久化技术无关的方式来进行访问的。持久化 方式的选择独立于Repository,同时只有数据访问相关的方法才通过接口进行暴露。这可以实现灵活的设计,并且切换持久化框架对应用 程序其他部分所带来的影响最小。如果将数据访问层的实现细节渗透到应用程序的其他部分中,那么整个应用程序将与数据访问层耦合在 一起,从而导致僵化的设计。

       Spring将数据访问过程中固定的和可变的部分明确划分为两个不同的类:模板(template)和回调(callback)。模板管理过程中固定的部 分,而回调处理自定义的数据访问代码。图10.2展现了这两个类的职 责。

SpringInAction笔记(十)——通过Spring和JDBC征服数据库 - 叶主任 - 叶主任的博客

    图10.2 Spring的数据访问模板类负责通用的数据访问功能。对于应用程序 特定的任务,则会调用自定义的回调对象

        如图所示,Spring的模板类处理数据访问的固定部分——事务控制、 管理资源以及处理异常。同时,应用程序相关的数据访问——语句、 绑定参数以及整理结果集——在回调的实现中处理。事实证明,这是一个优雅的架构,因为你只需关心自己的数据访问逻辑即可。
       针对不同的持久化平台,Spring提供了多个可选的模板。如果直接使 用JDBC,那你可以选择JdbcTemplate。如果你希望使用对象关系 映射框架,那HibernateTemplate或JpaTemplate可能会更适合 你。表10.2列出了Spring所提供的所有数据访问模板及其用途。
               表10.2 Spring提供的数据访问模板,分别适用于不同的持久化机制

SpringInAction笔记(十)——通过Spring和JDBC征服数据库 - 叶主任 - 叶主任的博客

 

10.2  配置数据源
        Spring提供了在Spring上下文中配置数据源bean的多种方式,包括:
        (1)通过JDBC驱动程序定义的数据源;
        (2)通过JNDI查找的数据源;
        (3)连接池的数据源。
        对于即将发布到生产环境中的应用程序,作者建议使用从连接池获取连接的数据源。如果可能的话,倾向于通过应用服务器的JNDI来获取数据源。

10.2.1 使用JNDI数据源
       Spring应用程序经常部署在Java EE应用服务器中,如WebSphere、 JBoss或甚至像Tomcat这样的Web容器中。这些服务器允许你配置通过 JNDI获取数据源。这种配置的好处在于数据源完全可以在应用程序之 外进行管理,这样应用程序只需在访问数据库的时候查找数据源就可以了。另外,在应用服务器中管理的数据源通常以池的方式组织,从而具备更好的性能,并且还支持系统管理员对其进行热切换。
(1) 首先修改tomcat的server.xml文件,位置: tomcat目录\conf\server.xml,在<GlobalNamingResources>结点下添加如下:

    <!--配置MySQL数据库的JNDI数据源-->
    <!-- 
       |- name:表示以后要查找的名称。通过此名称可以找到DataSource,此名称任意更换,但是程序中最终要查找的就是此名称,
                为了不与其他的名称混淆,所以使用jdbc/oracle,现在配置的是一个jdbc的关于oracle的命名服务。
       |- auth:由容器进行授权及管理,指的用户名和密码是否可以在容器上生效
       |- type:此名称所代表的类型,现在为javax.sql.DataSource
       |- maxActive:表示一个数据库在此服务器上所能打开的最大连接数
       |- maxIdle:表示一个数据库在此服务器上维持的最小连接数
       |- maxWait:最大等待时间。10000毫秒
       |- username:数据库连接的用户名
       |- password:数据库连接的密码
       |- driverClassName:数据库连接的驱动程序
       |- url:数据库连接的地址 
    -->
    <Resource name="jndi/spittrDB"   
              auth="Container"   
              type="javax.sql.DataSource"   
              driverClassName="com.mysql.jdbc.Driver"   
              url="jdbc:mysql://localhost:3306/spittr?characterEncoding=UTF-8"   
              username="root"   
              password="root"   
              maxActive="20"   
              maxIdle="10"   
              maxWait="10000"/> 

这是一个全局的配置,这时如果每个具体的context(webapp)中如果要引用这个resource,则需要在各个context对象中配置 resourcelink,然后在各个app的web.xml中配置<resource-ref>.

(2)在conf/context.xml里添加引用:

    <!-- global\name属性对应server.xml Resource的name属性-->
    <ResourceLink global="jndi/spittrDB"
    	            name="jndi/spittrDB"
                  auth="Container"
                  type="javax.sql.DataSource" />


(3)使用Java配置的话,那可以借助 JndiObjectFactoryBean从JNDI中查找DataSource:

    @Bean
    @Profile("jndi")
    public DataSourceInitializer dataSourceInitializer(DataSource dataSource) {
          System.out.println("生产环境初始化数据表");
          DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
          dataSourceInitializer.setDataSource(dataSource);
          ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
          //加载SQL文件
          databasePopulator.addScript(new ClassPathResource("spittr/data/schema_mysql.sql"));
          databasePopulator.addScript(new ClassPathResource("spittr/data/security_mysql.sql"));
          dataSourceInitializer.setDatabasePopulator(databasePopulator);
          dataSourceInitializer.setEnabled(true);
          return dataSourceInitializer;
   }
    
   @Bean(destroyMethod="")
   @Profile("jndi")
   public JndiObjectFactoryBean jndiDataSource() throws IllegalArgumentException, NamingException {
         JndiObjectFactoryBean jndiObjectFB = new JndiObjectFactoryBean();
         //jndiObjectFB.setJndiName("jndi/spittrDB");
         jndiObjectFB.setJndiName("java:comp/env/jndi/spittrDB");
         jndiObjectFB.setResourceRef(true);
         jndiObjectFB.setProxyInterface(javax.sql.DataSource.class);
         return jndiObjectFB;    
   }

JndiObjectFactoryBean是个工厂类,spring会自动调用JndiObjectFactoryBean的afterPropertiesSet()方法去造真正需要的bean,然后调用getObject()和getObjectType()方法返回已造好的datasource,再将其准确的注入依赖它的其他bean里面。这是最好的方式。      
       当然,也可以直接使用jndiObjectFB.getObject(),如下:

	@Bean(destroyMethod="")
	@Profile("jndi")
	public DataSource jndiDataSource() throws IllegalArgumentException, NamingException {
		JndiObjectFactoryBean jndiObjectFB = new JndiObjectFactoryBean();
		jndiObjectFB.setJndiName("java:comp/env/jndi/spittrDB");
		jndiObjectFB.setResourceRef(true);
		jndiObjectFB.setProxyInterface(javax.sql.DataSource.class);
		jndiObjectFB.afterPropertiesSet();
		return (DataSource) jndiObjectFB.getObject();	
	}

注意,在使用jndiObjectFB.getObject()之前,必须调用jndiObjectFB.afterPropertiesSet(),否则dataSource会为空。


10.2.2 使用数据源连接池
       尽管Spring并没有提供数据源连接池实现,但是我们有多项可用的方案,包括如下开源的实现:

  • Apache Commons DBCP (http://jakarta.apache.org/commons/dbcp);
  • c3p0 (http://sourceforge.net/projects/c3p0/) ;
  •  BoneCP (http://jolbox.com/) 。 

      这些连接池中的大多数都能配置为Spring的数据源,在一定程度上与 Spring自带的DriverManagerDataSource 或SingleConnectionDataSource很类似。
      以DBCP为例,使用MySQL数据库,配置DBCP BasicDataSource的XML方式:

<bean id="dataSource" class="org,apache.commons.dbcp.basicDataSource"
    p:driverClassName="com.mysql.jdbc.Driver"
    P:url="jdbc:mysql://localhost:3306/spittr?characterEncoding=UTF-8"
    p:uasername="root"
    p:initialSize="5"
    p:password="root"
    p:maxActive="10"/>

前四个属性是配置BasicDataSource所必需的。属性driverClassName指定了JDBC驱动类的全限定类名。在这里配置的是MySQL数据库的数据源。属性url用于设置数据库的JDBC URL。最后,username和password用于在连接数据库时进行认证。
       如果你喜欢Java配置的话,连接池形式的DataSourcebean可以声明如下:

	@Bean
	public DataSource mysqlDataSource() {
		BasicDataSource ds = new BasicDataSource();
		ds.setDriverClassName("com.mysql.jdbc.Driver");
		ds.setUrl("jdbc:mysql://localhost:3306/spittr?characterEncoding=UTF-8");
		ds.setUsername("root");
		ds.setPassword("");
		ds.setInitialSize(5);
		ds.setMaxActive(10);
		return ds;
	}

表10.3列出了DBCP BasicDataSource最有用的一些池配置属性:                                
      表10.3 BasicDataSource的池配置属性

SpringInAction笔记(十)——通过Spring和JDBC征服数据库 - 叶主任 - 叶主任的博客

        在我们的示例中,连接池启动时会创建5个连接;当需要的时候,允许BasicDataSource创建新的连接,但最大活跃连接数为10。

10.2.3  在Spring中使用JDBC

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

  • DriverManagerDataSource:在每个连接请求时都返回一个新建的连接。与DBCP的BasicDataSource不同,由DriverManagerDataSource提供的连接并没有进行池化管理;
  • SimpleDriverDataSource:与DriverManagerDataSource的工作方式类似,但是它直接使用JDBC驱动,来解决在特定环境下的类加载问题,这样的环境包括OSGi容器;
  • SingleConnectionDataSource:在每个连接请求时都会返回同一个的连接。尽管SingleConnectionDataSource不是严格意义上的连接池数据源,但是你可以将其视为只有一个连接的池。

以上这些数据源的配置与DBCP BasicDataSource的配置类似。例如,如下就是配置DriverManagerDataSource的方法 XML:

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" 
p:driverClassName="org.h2.Driver"
p:url="jdbc:h2:tcp://localhost/~/spitter"
P:username="sa"
p:password=""/>

Java配置:

    @Bean 
    public DriverManagerDataSource dataSource(){
        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setDriverClassName("org.h2.Driver");
        ds.setUrl("jdbc:h2:tcp://localhost/~/spitter");
        ds.setUsername("sa");
        ds.setPassword("");
        return ds;
    }



10.2.4 使用嵌入式的数据源
       嵌入式数据库 (embedded database)。嵌入式数据库作为应用的一部分运行,而不是应用连接的独立数据库服务器。对于开发和测试来讲,嵌入式数据库是很好的可选方案。这是因为每次重启应用或运行测试的时候,都能够重新填充测试数据。

       Spring的jdbc命名空间能够简化嵌入式数据库的配置。例如,如下的程序清单展现了如何使用jdbc命名空间来配置嵌入式的H2数据库, 它会预先加载两组测试数据。

	@Bean(destroyMethod="shutdown")
	public DataSource dataSource() {
		System.out.println("初始化数据库");
	    return new EmbeddedDatabaseBuilder()
	            .setType(EmbeddedDatabaseType.H2)
	            //初始化数据,chema.sql文件中包含用于创建数据表的关系
	            .addScript("classpath:spittr/data/schema.sql")
	            .addScript("classpath:spittr/data/h2_security.sql")
	            .setScriptEncoding("UTF-8")
	            .build();  
	}

 


10.2.5 使用profile选择数据源
       实际上,我们很可能面临 这样一种需求,那就是在某种环境下需要其中一种数据源,而在另外 的环境中需要不同的数据源。 在3.1版本中,Spring引入了bean profile的功能。要使用profile,你首先要将所有不同的bean定义整理到一个或多个profile之中,在将应用部署到每个环境时,要确保对应的profile处于激活(active)的状态。
        在Java配置中,可以使用@Profile注解指定某个bean属于哪一个profile。在Spring 3.1中,只能在类级别上使用@Profile注解。不过,从Spring 3.2开始,你也可以在方法级别上使用@Profile注解,与@Bean注解一同使用。

 

 

        例如,在测试环境中使用H2数据库,而在生产环境中使用MySQL数据库,DataConfig修改如下:

 

package spittr.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.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;

@Configuration
public class DataConfig {

	@Bean(destroyMethod="shutdown")
	@Profile("dev")
	public DataSource dataSource() {
		System.out.println("初始化数据库");
	    return new EmbeddedDatabaseBuilder()
	            .setType(EmbeddedDatabaseType.H2)
	            //初始化数据,chema.sql文件中包含用于创建数据表的关系
	            .addScript("classpath:spittr/data/schema.sql")
	            .addScript("classpath:spittr/data/h2_security.sql")
	            //.addScript("classpath:spittr/test/test-data.sql")
	            .setScriptEncoding("UTF-8")
	            .build();  
	}
	
	@Bean
	@Profile("prod")
	public DataSource mysqlDataSource() {
		BasicDataSource ds = new BasicDataSource();
		ds.setDriverClassName("com.mysql.jdbc.Driver");
		ds.setUrl("jdbc:mysql://localhost:3306/spittr?characterEncoding=UTF-8");
		ds.setUsername("root");
		ds.setPassword("root");
		ds.setInitialSize(5);
		ds.setMaxActive(10);
		return ds;
	}
	
	@Bean
	@Profile("prod")
    public DataSourceInitializer dataSourceInitializer(DataSource dataSource) {
		System.out.println("生产环境初始化数据表");
		DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
		dataSourceInitializer.setDataSource(dataSource);
		ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
		//加载SQL文件
		databasePopulator.addScript(new ClassPathResource("spittr/data/schema_mysql.sql"));
		databasePopulator.addScript(new ClassPathResource("spittr/data/security_mysql.sql"));
		dataSourceInitializer.setDatabasePopulator(databasePopulator);
		dataSourceInitializer.setEnabled(true);
		return dataSourceInitializer;
	}
	  
	@Bean
	public JdbcOperations jdbcTemplate(DataSource dataSource) {
	    return new JdbcTemplate(dataSource);  
	}
	
}

DataSourceInitializer来执行数据表的初始化工作,ResourceDatabasePopulator使用SQL脚本中定义的外部资源进行初始化或清理数据库。需添加以下3个jar包:commons-dbcp-1.4.jarcommons-pool-1.6.jarmysql-connector-java-5.1.38-bin.jar     在跑程序之前需执行两个MySQL脚本:

清单 schema_mysql.sql

DROP TABLE IF EXISTS Spittle;
create table Spittle (
	id int(10) NOT NULL auto_increment,
	message varchar(140) not null,
	created_at timestamp not null,
	latitude double,
	longitude double,
	PRIMARY KEY (id)
);

INSERT INTO Spittle (id, message, created_at, latitude, longitude) VALUES (1111, 'Spittles go fourth', '2018-02-24', 116.579618, 39.647447);

DROP TABLE IF EXISTS Spitter;
create table Spitter (
	id int(10) NOT NULL auto_increment,
	username varchar(20) unique not null,
	password varchar(20) not null,
	first_name varchar(30) not null,
	last_name varchar(30) not null,
	email varchar(30) not null,
	PRIMARY KEY (id)
);

 

清单 security_mysql.sql:

 

DROP TABLE IF EXISTS users;
create table users (
	id int NOT NULL auto_increment,
	username varchar(50) unique not null,
	password varchar(20) not null,
	enabled tinyint(4) default null,
	PRIMARY KEY (id)
);

DROP TABLE IF EXISTS authorities;
create table authorities (
	id int NOT NULL auto_increment,
	username varchar(50) unique not null,
	authority varchar(50) default null,
	PRIMARY KEY (id)
);

DROP TABLE IF EXISTS groups;
create table groups (
	id int,
	group_name varchar(50) not null,
	PRIMARY KEY (id)
);

DROP TABLE IF EXISTS group_members;
create table group_members (
	id int NOT NULL auto_increment,
	group_id int(11) not null,
	username varchar(50) not null,
	PRIMARY KEY (id)
);

DROP TABLE IF EXISTS group_authorities;
create table group_authorities (
	id int NOT NULL auto_increment,
	group_id int(11) not null,
	authority varchar(50) default null,
	PRIMARY KEY (id)
);

INSERT INTO users (username, password, enabled) VALUES ('username', '123456', 1);
INSERT INTO authorities (username, authority) VALUES ('username', 'ROLE_USER');
INSERT INTO groups (id, group_name) VALUES (1, 'group_name');
INSERT INTO group_members (group_id, username) VALUES (1, 'username');
INSERT INTO group_authorities (group_id, authority) VALUES (1, 'ROLE_USER');

       通过使用profile功能,会在运行时选择数据源,这取决于哪一个 profile处于激活状态。Spring在确定哪个profile处于激活状态时,需要依赖两个独立的属性:spring.profiles.active和spring.profiles.default。如果设置了spring.profiles.active属性的话,那么它的值就会用来确定哪个profile是激活的。但如果没有设置spring.profiles.active属性的话,那Spring将会查找spring.profiles.default的值。如果spring.profiles.active和spring.profiles.default均没有设置的话,那就没有激活的profile,因此只会创建那些没有定义在profile中的bean。     

      有多种方式来设置这两个属性:

  • 作为DispatcherServlet的初始化参数;
  • 作为Web应用的上下文参数;
  • 作为JNDI条目;
  • 作为环境变量;
  • 作为JVM的系统属性;在集成测试类上,使用@ActiveProfiles注解设置。  

      这里选择第一种方式,在AbstractAnnotationConfigDispatcherServletInitializer中设置:

package spittr.config;

import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class SpitterWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
  
	/**
	 * 将一个或多个路径映射到DispatcherServlet上
	 */
	@Override
	protected String[] getServletMappings() {  
		return new String[] { "/" };
	}
	
	/**
	 * 设置spring上下文配置类
	 */
	@Override
	protected Class<?>[] getRootConfigClasses() {
		return new Class<?>[] { RootConfig.class };
	}
 
	/**
	 * 设置springmvc上下文配置类
	 * 当DispatcherServlet启动的时候,它会创建Spring应用上下文,并加载配置类或配置文件中所声明的bean
	 */
	@Override 
	protected Class<?>[] getServletConfigClasses() {   
		return new Class<?>[] { WebConfig.class }; 
	}

	@Override
	protected void customizeRegistration(Dynamic registration) {
		// TODO Auto-generated method stub
		registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads", 2097152,4194304,0));
	}

	@Override
	public void onStartup(ServletContext servletContext)
			throws ServletException {
		// TODO Auto-generated method stub
		super.onStartup(servletContext);
		servletContext.setInitParameter("spring.profiles.active", "prod");
	}
 
}

将数据库设置为生产环境,即使用MySQL数据库。当程序运行时,会自动选择MySQL数据库。

10.3 在Spring中使用JDBC
       JDBC不要求我们掌握其他框架的查询语言。它是建立在SQL之上的,而SQL本身就是数据访问语言。此外,与其他的技术相比,使用JDBC能够更好地对数据访问的性能进行调优。JDBC允许你使用数据库的所有特性,而这是其他框架不鼓励甚至禁
止的。

10.3.2 使用JDBC模板
      Spring的JDBC框架承担了资源管理和异常处理的工作,从而简化了JDBC代码,让我们只需编写从数据库读写数据的必需代码。
Spring为JDBC提供了三个模板类供选择:

  • jdbcTemplate:最基本的Spring JDBC模板,这个模板支持简单的JDBC数据库访问功能以及基于索引参数的查询;
  • NamedParameterJDBCTemplate:使用该模板类执行查询时可以将值以命名参数的形式绑定到SQL中,而不是使用简单的索引参数;
  • SimpleJDBCTemplate:该模板类利用Java5的一些特性如自动装箱、泛型以及可变参数列表来简化JDBC模板的使用。

        从Spring3.1开始,SimpleJDBCTemplate已经被废弃,器Java5的特性被转移到了jdbcTemplate中,并且只有在你需要使用命名参数的时候,才需要使用NamedParameterJDBCTemplate。这样的话,对于大多数的JDBC任务来说,jdbcTemplate就是最好的可选方案

使用JdbcTemplate来插入数据

       为了让JdbcTemplate正常工作,只需要为其设置DataSource就可以了,这使得在Spring中配置JdbcTemplate非常容易,如下面的@Bean方法所示:

@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource){
    return new JdbcTemplate(dataSource);
}

 

现在,我们可以将jdbcTemplate装配到Repository中并使用它来访问数据库。例如,SpitterRepository使用了JdbcTemplate:

 

@Repository
public class JdbcSpitterRepository implements SpitterRepository {
	 
	private JdbcOperations jdbc;
	  
	@Autowired 
	public JdbcSpitterRepository(JdbcOperations jdbc) {	    
		this.jdbc = jdbc;  
	}
        ...
}

JdbcOperations是一个接口,定义了JdbcTemplate所实现的操作。通过注入JdbcOperations,而不是具体的JdbcTemplate,能够保证JdbcSpitterRepository通过JdbcOperations接口达到与JdbcTemplate保持松耦合。       在Repository中具备可用的JdbcTemplate后,我们可以极大地简化程序清单10.4中的addSpitter()方法。基于JdbcTemplate的addSpitter()方法如下:

	public Spitter addSpitter(Spitter spitter) {
		// TODO Auto-generated method stub    
		jdbc.update(
	    		"insert into Spitter (username, password, first_name, last_name, email)" +
	            " values (?, ?, ?, ?, ?)",
	            spitter.getUsername(),
	            spitter.getPassword(),
	            spitter.getFirstName(),
	            spitter.getLastName(),
	            spitter.getEmail());     
		return spitter;
	}

 


使用JdbcTemplate来读取数据
       程序清单10.8展现了新版本的findOne()方法,它使用了JdbcTemplate的回调,实现根据ID查询Spitter,并将结果集映射为Spitter对象。

 

 

                                             程序清单10.8 使用JdbcTemplate查询Spitter

 

	public Spitter findByUsername(String username) {
		// TODO Auto-generated method stub
	    return jdbc.queryForObject(
	    		"select id, username, password, first_name, 
                 last_name, email from Spitter where username=?", 
	            new SpitterRowMapper(), 
	            username);
	}
  
	private static class SpitterRowMapper implements RowMapper<Spitter> {	    
		public Spitter mapRow(ResultSet rs, int rowNum) throws SQLException {	      
			return new Spitter(
		          rs.getLong("id"),
		          rs.getString("username"),
		          null,
		          rs.getString("first_name"),
		          rs.getString("last_name"),
		          rs.getString("email"));	    
		}		  
	}


queryForObject()方法有三个参数:

 

  • String对象,包含了要从数据库中查找数据的SQL;
  • RowMapper对象,用来从ResultSet中提取数据并构建域对象(本例中为Spitter);
  • 可变参数列表,列出了要绑定到查询上的索引参数值。

       SpitterRowMapper对象实现了RowMapper接口。对于查询返回的每一行数据,JdbcTemplate将会调用RowMapper的mapRow()方法,并传入一个ResultSet和包含行号的整数。在SpitterRowMapper的mapRow()方法中,我们创建了Spitter对象并将ResultSet中的值填充进去。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值