jdbcTemplate使用
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.0.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
<!-- spring里面自带了一个连接池,, 也可以用druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.12</version>
</dependency>
</dependencies>
@Configuration
@PropertySource("classpath:db.properties")
@Data
public class JavaConfig {
@Value("${db.username}")
private String username;
@Value("${db.password}")
private String password;
@Value("${db.url}")
private String url;
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setUsername(username);
ds.setUrl(url);
ds.setPassword(password);
return ds;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource){
return new JdbcTemplate(dataSource);
}
}
public class Demo {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(JavaConfig.class);
JdbcTemplate jdbcTemplate = ctx.getBean(JdbcTemplate.class);
// // ddl 创建一张表,修改一个表的结构 data definition language 表定义操作
// jdbcTemplate.execute();
// // 批处理,调用这个方法
// jdbcTemplate.batchUpdate();
// // 增删改
// jdbcTemplate.update();
// jdbcTemplate.query();
// jdbcTemplate.queryForList();
// ddl data definition language
// jdbcTemplate.execute();
// 批处理
// jdbcTemplate.batchUpdate()
// jdbcTemplate.queryForList()
// jdbcTemplate.query()
// add(jdbcTemplate);
// update(jdbcTemplate);
// delete(jdbcTemplate);
// query2(jdbcTemplate);
// query3(jdbcTemplate);
// query4(jdbcTemplate);
// query5(jdbcTemplate);
query6(jdbcTemplate);
}
private static void add(JdbcTemplate jdbcTemplate){
int row = jdbcTemplate.update("insert into user(name,address) values (?,?)", "cc", "chengdu");
System.out.println("row = " + row);
}
private static void update(JdbcTemplate jdbcTemplate){
int row = jdbcTemplate.update("update user set address = ? where id=? ", "beijing", 1);
System.out.println("row = " + row);
}
private static void delete(JdbcTemplate jdbcTemplate){
int row = jdbcTemplate.update("delete from user where id =?", 4);
System.out.println("row = " + row);
}
public static void query(JdbcTemplate jdbcTemplate){
jdbcTemplate.query("select * from user where address = ?", new RowCallbackHandler() {
@Override
public void processRow(ResultSet rs) throws SQLException {
// 外面声明一个list
}
},"chengdu");
}
public static void query2(JdbcTemplate jdbcTemplate){
List<User> list = jdbcTemplate.query("select * from user where address = ?", new RowMapper<User>() {
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
user.setAddress(rs.getString("address"));
return user;
}
}, "chengdu");
System.out.println(Arrays.toString(list.toArray()));
}
public static void query3(JdbcTemplate jdbcTemplate){
// 自动将查询结果 映射到对象上,,, 前提是查询的结果的列名称必须和实体的属性名称保持一致
// 属性对不上,使用RowMapper自己去做一一映射
List<User> list = jdbcTemplate.query("select * from user where address = ?", new BeanPropertyRowMapper<>(User.class), "chengdu");
System.out.println(Arrays.toString(list.toArray()));
}
public static void query4(JdbcTemplate jdbcTemplate){
// 查询一个用户
User user = jdbcTemplate.queryForObject("select * from user where id = ?", new BeanPropertyRowMapper<>(User.class), 1);
System.out.println("user = " + user);
}
public static void query5(JdbcTemplate jdbcTemplate){
// 第二个参数,,设置普通对象,,,查询结果只能返回一列
String name = jdbcTemplate.queryForObject("select name from user where id = ?", String.class, 1);
System.out.println("name = " + name);
}
public static void query6(JdbcTemplate jdbcTemplate){
// queryForList只能有一列,不能有多列
List<String> users = jdbcTemplate.queryForList("select name from user", String.class);
System.out.println(Arrays.toString(users.toArray()));
}
}
传统的jdbcTemplate都是用 ?
做占位符,, ,,也可以不使用?
而是使用变量名称来传递参数。。使用NamedParameterJdbcTemplate
…避免问号的顺序搞反了,
@Bean
public NamedParameterJdbcTemplate namedParameterJdbcTemplate(){
return new NamedParameterJdbcTemplate(dataSource());
}
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(JavaConfig.class);
NamedParameterJdbcTemplate jdbcTemplate = ctx.getBean(NamedParameterJdbcTemplate.class);
Map<String, Object> map = new HashMap<>();
map.put("id",2);
map.put("address","chengdu");
List<User> list = jdbcTemplate.query("select * from user where id>:id and address = :address", map, new BeanPropertyRowMapper<>(User.class));
System.out.println(Arrays.toString(list.toArray()));
事务
事务的四大特性
acid
- atomicity : 原子性,,, 一个事务中的所有操作,要么全部完成,要么全部不完成
- consistency : 一致性 ,,, 事务开始之前和事务结束之后,数据库的完整性没有被破坏
- isolation : 隔离性,, 多个事务执行,会隔离,,事务隔离等级:读未提交,读已提交,可重复读,串行化
- durability : 持久性,,,事务结束之后,对数据的修改是永久的
spring中的事务
编程式事务:
使用TransactionManager,, 先传入数据源配置一个TransactionManager,
/**
* 事务管理器
* @return
*/
@Bean
PlatformTransactionManager platformTransactionManager(){
return new DataSourceTransactionManager(dataSource());
}
transaction.getTransaction()
获取一个事务,,
transaction.commit()
: 提交事务
transaction.rollback()
: 回滚事务
public void transfer(String from,String to,Double money){
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(definition);
try {
accountDao.minusMoney(from,money);
// int i = 1/0;
accountDao.addMoney(to,money);
// 提交事务
transactionManager.commit(status);
} catch (Exception e) {
System.out.println(e.getMessage());
// 回滚事务
transactionManager.rollback(status);
}
}
}
也可以用 transactionTemplate ,, spring利用aop的思想,把很多重复的东西封装了,比如jdbcTeamplate,transactionTemplate
@Bean
TransactionTemplate transactionTemplate(){
// 传入一个 transactionManager
return new TransactionTemplate(platformTransactionManager());
}
public void transfer(String from,String to,Double money){
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
accountDao.minusMoney(from,money);
int i = 1/0;
accountDao.addMoney(to,money);
}
});
}
编程式事务一般不用,因为还是有侵入的代码,事务和业务的代码混在一起
声明式事务
声明式事务本质上是aop,,需要配置tx:advice ,,事务的通知,,也就是需要被增强的方法名字,,,
aop将这个通知配置进去。。。
声明式事务底层就是aop,需要添加包:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>6.0.4</version>
</dependency>
<?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:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.cj.ts02"/>
<context:property-placeholder location="db.properties"/>
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</bean>
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 声明式事务,本质还是aop-->
<!-- 要增强的方法-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 配置事务的属性,哪些方法要加事务,可以使用通配符 -->
<tx:method name="transfer"/>
<!-- <tx:method name="add*"/>-->
</tx:attributes>
</tx:advice>
<!-- aop配置,,, 相当于把这个transfer方法动态代理了,,-->
<aop:config>
<aop:pointcut id="pc" expression="execution(* com.cj.ts02.AccountService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/>
</aop:config>
</beans>
java代码实现事务:使用EnableTransactionManager
开启事务,,开启了之后,,就能直接使用@Transactional
注解去标识,哪个方法要有事务
@Configuration
@ComponentScan(basePackages = "com.cj.ts02")
@PropertySource("classpath:db.properties")
// 开启事务注解,, 开了之后只需要在方法上添加 @Transactional 即可
@EnableTransactionManagement
public class JavaConfig {
@Value("${db.url}")
private String url;
@Value("${db.username}")
private String username;
@Value("${db.password}")
private String password;
@Bean
public JdbcTemplate jdbcTemplate(){
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
return jdbcTemplate;
}
@Bean
DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setUsername(username);
ds.setPassword(password);
ds.setUrl(url);
return ds;
}
/**
* 事务管理器
* @return
*/
@Bean
PlatformTransactionManager platformTransactionManager(){
return new DataSourceTransactionManager(dataSource());
}
}
java和xml结合使用,,, 在xml中可以使用<tx:annotation-driven/>
: 这个配置表示启用事务注解,,相当于@EnableTransactionManager
在spring中加事务的方式都一样,,,spring中将事务的实现都抽象出来了,有一套抽象的解决方案,,,框架只需要实现接口,就能使用spring中的事务
TransactionManager : 事务管理器
TransactionDefinition : 事务的定义
TransactionStatus : 事务的状态
PlatformTransactionManager
- getTransaction()