JdbcTemplate类对sql的操作使用

本文介绍了如何通过DBCP配置单连接数据源,并将其与Spring的JdbcTemplate集成以实现数据库操作。具体包括了数据源配置、JdbcTemplate实例化及DAO层的实现方法。
	<!--方式一: dbcp 数据源配置,在测试环境使用单连接 -->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<property name="url" value="jdbc:mysql://localhost:3306/police" />
		<property name="username" value="root" />
		<property name="password" value="root" />
	</bean>

  

    <!-- spring jdbcTemplate sql 查询-->
	<bean id="jdbcTemplate"	class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource" />
	</bean>
	<bean id="baseDao" class="com.dao.BaseDaoImpl"> <!-- dao 层使用 jdbcTemplate -->
		<property name="jdbcTemplate" ref="jdbcTemplate" />
	</bean>

  DAO底层使用 JdbcTemplate 

  JdbcTemplate jdbcTemplate;

    private JdbcTemplate jdbcTemplate;

    /*set get 封装方法*/
       //简单的列表
	public List<Map<String, Object>> queryForList(String sql) {
		return this.getJdbcTemplate().queryForList(sql);
	}	
	
	public Map<String, Object> queryForMap(String sql) {
		return this.getJdbcTemplate().queryForMap(sql);
	}

 query 方法:

 

转载于:https://www.cnblogs.com/estellez/p/4569172.html

<think>我们被要求使用JdbcTemplate在微服务架构中执行原生SQL语句。根据引用[3],我们知道在Spring中可以使用MyBatis执行原生SQL,但这里我们直接使用JdbcTemplate。 引用[4]提到了JDBC连接池和JdbcTemplate,说明JdbcTemplate是对JDBC的封装,简化了数据库操作。 由于是在微服务架构中,我们通常使用Spring Boot,而JdbcTemplate是Spring框架的一部分,因此我们可以很方便地使用它。 我们需要创建一个静态工具,其中包含使用JdbcTemplate执行原生SQL的方法。但是,注意JdbcTemplate本身不是线程安全的,但Spring中的JdbcTemplate被设计为可以在多线程环境下使用,因为它是无状态的(除了配置信息,而配置信息通常在初始化后不再改变)。因此,我们可以将JdbcTemplate作为工具的静态成员,但需要确保它被正确初始化。 然而,通常我们通过依赖注入来获取JdbcTemplate的bean,然后在工具使用。但是工具要求静态方法,所以我们需要在工具中持有JdbcTemplate的静态实例。 但是,在Spring中,我们无法直接将一个bean注入到静态变量中(至少不是直接支持),因此我们需要通过一些方式来实现。 常见做法: 1. 使用@PostConstruct方法在非静态bean中设置静态变量(但要注意,这可能会导致并发问题,因为Spring bean默认是单例的,所以设置一次即可,但要注意多线程安全)。 2. 使用ApplicationContextAware接口来获取bean。 但是,静态工具的方式可能不是最佳实践,因为这样会破坏Spring的依赖注入机制。我们也可以考虑不使用静态工具,而使用Spring的bean来管理。但既然用户要求静态工具,我们可以实现一个。 另外,引用[2]提到了JDBC工具的封装,并指出使用静态方法,但同时也提到了事务问题。如果我们需要在同一个事务中执行多个SQL,那么必须保证使用同一个连接。在JdbcTemplate中,它默认会从连接池获取连接并在操作完成后释放。如果我们希望多个操作在同一个事务中,应该使用声明式事务(@Transactional)或者编程式事务(TransactionTemplate)。 因此,在静态工具中,如果我们只是执行单个SQL语句,那么没有问题。但如果要执行多个SQL并保证事务,则需要额外处理。 鉴于以上,我们设计一个静态工具,它能够执行原生SQL(查询和更新),但不处理事务(事务由调用方通过Spring事务管理)。如果调用方需要事务,应该将包含多次调用工具的方法放在一个事务中(通过@Transactional)。 步骤: 1. 创建一个工具,例如JdbcTemplateUtils。 2. 在中定义一个静态的JdbcTemplate变量。 3. 提供一个初始化方法(通过Spring的bean来设置这个静态变量)。 但是,注意:在微服务中,可能有多个数据源,所以我们的工具应该支持多个数据源吗?还是只使用默认的JdbcTemplate?这里我们假设使用默认的一个数据源。 如果项目中有多个数据源,那么我们需要在工具中维护多个JdbcTemplate实例?或者指定一个默认的?这需要根据需求。为了简化,我们假设只有一个数据源。 实现: 首先,我们需要一个配置(或者在一个Spring管理的bean中)来设置静态的JdbcTemplate。 工具代码示例: 注意:由于静态变量在Spring容器启动时可能还没有被初始化,所以我们需要确保在使用工具之前,Spring容器已经将JdbcTemplate的bean设置到工具中。 我们可以这样写: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; @Component public class JdbcTemplateUtils { private static JdbcTemplate staticJdbcTemplate; @Autowired private JdbcTemplate jdbcTemplate; @PostConstruct public void init() { staticJdbcTemplate = this.jdbcTemplate; } public static int executeUpdate(String sql, Object... args) { return staticJdbcTemplate.update(sql, args); } public static <T> T executeQuery(String sql, RowMapper<T> rowMapper, Object... args) { return staticJdbcTemplate.queryForObject(sql, rowMapper, args); } // 可以添加更多的执行方法,如查询返回List等 } ``` 但是,上面的工具本身是一个Spring bean(通过@Component),然后通过@PostConstruct将注入的jdbcTemplate赋值给静态变量。这样,我们就可以通过静态方法调用JdbcTemplate了。 然而,这里有一个问题:在Spring容器启动过程中,当JdbcTemplateUtils被初始化后,staticJdbcTemplate就被赋值了,此后就可以使用静态方法。但是,如果多个数据源,我们这里只注入了一个JdbcTemplate(默认的)。如果项目中有多个数据源,那么需要指定一个特定的数据源对应的JdbcTemplate。 另外,注意上面的查询方法中,我们使用了queryForObject,这个方法只适用于返回单个对象的情况。对于返回多个对象的情况,我们可以提供其他的方法。 另外,我们也可以直接提供执行任意SQL的方法,比如使用execute方法执行DDL语句。 但是,请注意,引用[3]提到,执行原生SQL时,结果集的处理需要自己完成。在JdbcTemplate中,我们可以使用RowMapper或者ResultSetExtractor来自定义结果映射。 因此,我们可以提供多种执行方法。 但是,为了简单,我们可以只提供几个常用方法: 1. 执行更新(insert, update, delete) 2. 查询单个对象(queryForObject) 3. 查询列表(queryForList) 4. 执行任意SQL(包括DDL)的execute方法 另外,我们还可以提供不参数的方法。 考虑到工具的通用性,我们可以这样设计: ```java import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.RowMapperResultSetExtractor; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.util.List; @Component public class JdbcTemplateUtils { private static JdbcTemplate staticJdbcTemplate; // 通过构造器或setter注入,这里使用setter注入(也可以使用Autowired) @Autowired public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { staticJdbcTemplate = jdbcTemplate; } // 更新操作 public static int update(String sql, Object... args) { return staticJdbcTemplate.update(sql, args); } // 查询单个对象 public static <T> T queryForObject(String sql, Class<T> requiredType) { return staticJdbcTemplate.queryForObject(sql, requiredType); } public static <T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args) { return staticJdbcTemplate.queryForObject(sql, rowMapper, args); } // 查询列表 public static <T> List<T> queryForList(String sql, Class<T> elementType) { return staticJdbcTemplate.queryForList(sql, elementType); } public static <T> List<T> query(String sql, RowMapper<T> rowMapper, Object... args) { return staticJdbcTemplate.query(sql, args, new RowMapperResultSetExtractor<>(rowMapper)); } // 执行任意SQL(无返回值) public static void execute(String sql) { staticJdbcTemplate.execute(sql); } } ``` 注意:上面的setJdbcTemplate方法使用了@Autowired,这样Spring会自动注入。但是,由于我们只有一个JdbcTemplate(默认数据源),所以可以这样写。如果有多个,我们需要指定其中一个。 另外,上面的query方法中,我们使用了RowMapperResultSetExtractor,实际上JdbcTemplate有更直接的query方法,我们可以直接调用: ```java public static <T> List<T> query(String sql, RowMapper<T> rowMapper, Object... args) { return staticJdbcTemplate.query(sql, rowMapper, args); } ``` 这样更简洁。 但是,请注意,如果静态方法在Spring容器初始化之前被调用,那么staticJdbcTemplate为null,会导致空指针异常。因此,要确保在Spring容器初始化完成后再使用这些静态方法。 另外,由于我们使用了@Component,所以这个会被Spring扫描并创建bean,然后注入JdbcTemplate。所以,在Spring上下文初始化完成后,staticJdbcTemplate会被赋值。 但是,如果用户希望在非Spring管理的使用,那么要确保使用的时候Spring容器已经初始化完成。 另外,关于事务:我们前面提到,这个工具不管理事务。如果需要事务,应该在调用方法上添加@Transactional注解(在Spring管理的bean中)。 示例用法(在Spring管理的bean中): ```java @Service public class SomeService { @Transactional public void doBusiness() { // 执行多个数据库操作 JdbcTemplateUtils.update("update table1 set col1=? where id=?", value1, id1); JdbcTemplateUtils.update("update table2 set col2=? where id=?", value2, id2); } } ``` 这样,两个更新操作会在同一个事务中。 但是,如果我们在非Spring管理的中调用,那么就无法使用声明式事务了。因此,建议在Spring管理的bean中使用这个工具,以便可以配合事务。 另外,我们也可以考虑在工具中支持编程式事务,但那样会使工具变得复杂。因此,这里我们不考虑。 最后,关于微服务架构:每个微服务通常有自己的数据库,所以这个工具操作当前微服务的数据库。 总结:我们创建了一个静态工具,通过Spring注入JdbcTemplate,然后提供静态方法来执行原生SQL。 但是,请注意,在Spring Boot中,我们通常不需要自己创建JdbcTemplate,因为Spring Boot已经自动配置了一个。我们只需要在配置文件中配置好数据源,Spring Boot就会自动创建一个JdbcTemplate bean。 因此,在微服务中,我们只需要在配置文件中配置好数据库连接,然后就可以使用这个工具了。 配置文件示例(application.yml): ```yaml spring: datasource: url: jdbc:mysql://localhost:3306/test username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver ``` 然后,在Spring Boot主所在的包或其子包中,工具会被扫描到,并完成注入。 如果工具不在扫描包下,可以通过其他方式注入,比如在配置中显式定义bean(但通常不需要,因为@Component会被扫描)。 注意事项: 1. 工具在Spring容器初始化完成前不可用。 2. 不支持多数据源(默认使用主数据源对应的JdbcTemplate)。 3. 事务由调用方通过Spring事务管理。 如果项目中需要多数据源,那么我们需要修改工具,使其能够根据数据源名称来获取对应的JdbcTemplate。这需要维护一个Map,将数据源名称和JdbcTemplate关联起来。但是,这超出了简单工具的范畴,建议在需要多数据源时,使用Spring的AbstractRoutingDataSource或者为每个数据源单独创建工具实例(这时静态工具就不适用了)。 因此,对于多数据源的情况,我们不推荐使用静态工具,而是推荐使用每个数据源对应的Service,或者使用Spring的依赖注入来获取指定数据源的JdbcTemplate。 以上,我们完成了静态工具的设计。 相关问题: 1. 在静态工具中如何保证JdbcTemplate的线程安全? 答:JdbcTemplate本身是线程安全的,因为它是无状态的(除了配置信息,而配置信息在创建后不可变),所以多个线程可以共享同一个JdbcTemplate实例。 2. 如何在这个工具中处理事务? 答:我们不建议在工具内部处理事务,而是应该由调用方通过Spring的事务管理(声明式或编程式)来管理事务。 3. 如果微服务中有多个数据源,这个工具该如何扩展? 答:可以修改工具,使其持有一个Map<String, JdbcTemplate>,然后通过数据源名称来获取对应的JdbcTemplate。初始化时,需要将所有数据源的JdbcTemplate都注入到工具中。然后静态方法需要增加一个数据源名称的参数。 4. 执行原生SQL时,如何防止SQL注入? 答:JdbcTemplate使用预编译语句(PreparedStatement)来执行SQL,所以我们使用参数化查询(如update(sql, args))就可以防止SQL注入。避免直接拼接SQL字符串。 5. 工具中的静态方法在Spring容器启动前被调用怎么办? 答:应该避免这种情况,确保在Spring容器初始化完成后再调用这些方法。如果确实需要在容器启动过程中执行,可以考虑使用事件监听器(ApplicationListener)来在容器初始化完成后执行。 6. 工具中如何执行存储过程? 答:可以增加调用存储过程的静态方法,使用JdbcTemplate的call方法。 根据以上,我们生成相关问题: §§相关问题§§ 1. 如何在静态工具中支持多数据源? 2. 如何防止在使用JdbcTemplate执行SQL时发生SQL注入? 3. 在非Spring管理的中如何使用这个工具并保证事务? 4. 这个工具在微服务启动时如何初始化? 5. 除了增删改查,JdbcTemplate还能执行哪些型的SQL?</think>### 使用静态工具通过JdbcTemplate执行原生SQL的实现方案 在微服务架构中,通过静态工具执行原生SQL需结合Spring的依赖注入机制和线程安全设计。以下是具体实现步骤和代码示例: #### 1. **创建静态工具** ```java import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; @Component public class SqlExecutor { private static JdbcTemplate staticJdbcTemplate; private final JdbcTemplate jdbcTemplate; // 通过构造器注入 public SqlExecutor(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @PostConstruct public void init() { staticJdbcTemplate = this.jdbcTemplate; } // 执行更新操作 public static int executeUpdate(String sql, Object... params) { return staticJdbcTemplate.update(sql, params); } // 执行查询操作 public static <T> T executeQuery(String sql, RowMapper<T> rowMapper, Object... params) { return staticJdbcTemplate.queryForObject(sql, rowMapper, params); } } ``` #### 2. **关键设计说明** 1. **依赖注入** - 通过构造器注入`JdbcTemplate`实例,确保工具与Spring容器解耦[^2] - `@PostConstruct`在Bean初始化时将实例赋值给静态变量,解决静态方法无法直接注入的问题 2. **线程安全** - `JdbcTemplate`本身是线程安全的,可被多线程共享[^4] - 静态变量`staticJdbcTemplate`在初始化后不再修改,避免并发问题 3. **事务管理** - **声明式事务**:在Service层使用`@Transactional`注解 ```java @Service public class UserService { @Transactional public void updateUser(String sql) { SqlExecutor.executeUpdate(sql); // 自动参与事务 } } ``` - **编程式事务**:通过`TransactionTemplate`手动控制 ```java public void batchUpdate(List<String> sqlList) { transactionTemplate.execute(status -> { sqlList.forEach(SqlExecutor::executeUpdate); return null; }); } ``` #### 3. **使用示例** ```java // 更新操作 String updateSql = "UPDATE users SET status = ? WHERE id = ?"; int rows = SqlExecutor.executeUpdate(updateSql, "active", 1001); // 查询操作 String querySql = "SELECT * FROM products WHERE price > ?"; List<Product> products = SqlExecutor.executeQuery( querySql, (rs, rowNum) -> new Product(rs.getString("name"), rs.getDouble("price")), 50.0 ); ``` #### 4. **性能优化建议** 1. **连接池配置** 在`application.yml`中优化连接池: ```yaml spring: datasource: hikari: maximum-pool-size: 20 connection-timeout: 3000 ``` 2. **批处理支持** 添加批处理方法: ```java public static int[] batchUpdate(String sql, List<Object[]> paramsList) { return staticJdbcTemplate.batchUpdate(sql, paramsList); } ``` 3. **SQL注入防护** 始终使用参数化查询(如示例中的`Object... params`),避免拼接SQL字符串[^2] > **注意事项** > - 确保工具在Spring容器初始化完成后使用 > - 复杂结果集处理建议配合`BeanPropertyRowMapper` > - 多数据源场景需扩展工具支持`@Qualifier`注入 --- ### 相关问题 1. **静态工具中如何保证多数据源支持?** 需扩展工具维护`Map<String, JdbcTemplate>`,通过数据源标识符动态切换[^2] 2. **JdbcTemplate执行存储过程的最佳实践?** 使用`SimpleJdbcCall`封装存储过程调用,需处理输出参数和结果集映射 3. **原生SQL查询结果如何自动映射到DTO对象?** 结合`BeanPropertyRowMapper`或自定义`ResultSetExtractor`实现对象转换 4. **高并发场景下如何优化静态工具的性能?** 重点监控连接池配置(最大连接数/超时设置)和批处理能力[^4] 5. **工具如何兼容Spring Boot 3.x的JDBC新特性?** 需适配`JdbcClient`接口和响应式编程模型,支持非阻塞IO操作 [^1]: Spring通过模板方法等设计模式封装JDBC操作,简化数据库访问复杂度 [^2]: 静态工具需解决连接池管理和事务一致性挑战 [^3]: 原生SQL执行需手动处理结果集映射,TypeHandler不生效 [^4]: 连接池技术复用连接对象,显著提升数据库操作性能
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值