Spring入门后半部分----JDBCTemplate和事务控制
Posted 大忽悠爱忽悠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring入门后半部分----JDBCTemplate和事务控制相关的知识,希望对你有一定的参考价值。
JDBCTemplate和事物控制
- JDBCTemplate基本使用,承接上半部分
- 声明式事务
- 声明式事务
- 事务管理器(事务切面)
- @Transactional注解里面的属性分析
- timeout---->参数值为int(秒为单位),超时,事务超出指定执行时长后自动终止并回滚
- readOnly---->参数值为bool,设置事务为只读,可以进行事务优化,默认readOnly=false,改为readOnly=true后,可以加快查询速度,因此不用管事务的相关操作了(设置自动提交....)
- 如果事务方法中有增删改相关操作,还设置为true时,运行时会报错
- 异常分类
- noRollbackFor---->参数值为Class[] (字节码文件类型,是个数组) ,那些异常事务可以不回滚
- noRollbackForClassName---->参数值为String[] (全类名) ,那些异常事务可以不回滚
- rollbackFor---->参数值为Class[] (字节码文件类型) ,哪些异常事务需要回滚
- rollbackForClassName---->参数值为String[] (全类名),哪些异常事务需要回滚
- ioslation调整隔离级别
- 事务传播行为(事务的传播和事务的行为)
- 简单理解: 一个事务相等于一辆车,如果子事务和大事务共同用一个事务,那么可以理解为子事务和大事务位于同一辆车上。如果子事务开启一个新事务,相当于子事务开了一辆新车,大事务和子事务位于不同的车上面
- 注意: 出现的异常回一层一层往上面进行传递,坐一辆车的全崩,开新车并且在异常之前执行的不崩;开新车,但是位于异常之后,崩。
- 注意:如果子事务出现了异常,并且子事务位于大事务的方法体内部,那么大事务会感受到异常,那么即便大事务和子事务开不同的车,大事务也会崩掉,因为方法体内部出现了异常
- 子事务只和上一级的事务坐一辆车,不会和上一级的上一级的事务坐一辆车,除非他的上一级的事务和他的上一级的上一级的事务坐一辆车
- 总结图
- 设置事务传播行为演示
- 重点:REQUIRED事务属性来源于大事务(子事务和大事务坐一辆车时),即子事务的所有属性,例如超时设置,回滚设置,都继承于大事务,即使子事务里面设置了,也没有用
- propagation = Propagation.REQUIRES_NEW可以调整,默认是REQUIRED
- REQUIRED将之前事务使用的connection传递给这个事务使用
- REQUIRED_NEW这个方法直接使用新的connection
- 本类事务方法之间的调用就只是一个事务
- 在本类中给本类对象进行注入,会造成死循环
- 事务控制的xml配置:依赖tx名称空间和aop名称空间
- 要导入spring-tx坐标,spring处理事务相关的坐标
- 切点方法事务配置参数
JDBCTemplate基本使用,承接上半部分
抽取数据库连接池配置时填入的参数,放到properties配置文件中
properties配置文件:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test1
jdbc.username=root
jdbc.password=126433
在Spring容器中引入pro配置文件,然后修改刚才传入的参数—配置数据库的模板
注意: ${}取出配置文件中的值 ,#{}是Spring的表达式语言
<!--加载jdbc.properties-->
<!--引入context命名空间-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--数据源对象-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--jdbc模板对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
在主类中向数据库插入数据
public class jdbc {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("appOfDao.xml");
JdbcTemplate jt = app.getBean(JdbcTemplate.class);
int row = jt.update("insert account values (?,?),(?,?)", "大忽悠", 8000, "小朋友", 6000);
System.out.println("影响的行数"+row);
}
}
批量插入的方法
ApplicationContext app = new ClassPathXmlApplicationContext("appOfDao.xml");
JdbcTemplate jt = app.getBean(JdbcTemplate.class);
String sql="insert into account values(?,?)";
//List<Object[]>
//List的长度就是sql语句要执行的次数
//Object[]:每次执行要用的参数
ArrayList<Object[]> obj = new ArrayList<Object[]>();
obj.add(new Object[]{"张三",7000});
obj.add(new Object[]{"李四",8000});
obj.add(new Object[]{"王五",9000});
obj.add(new Object[]{"赵六",6000});
//返回的是一个数组,表示每条sql语句影响的行数
int[] is = jt.batchUpdate(sql, obj);
for(int i:is)
System.out.println("影响的行数:"+i);
查询某条记录,封装为一个java对象,并返回
JavaBean对象的属性名需要和数据库中的字段名一致,否则无法完成数据的封装,当前也可以在编写查询sql语句的时候,通过对数据库每列的名称起一个别名,来达到封装的目的
这里的属性名依旧是set方法,去掉set,首字母小写得到的字符串,因此set方法必不可少
jdbcTemplate在方法级别进行了区分: 查询集合,查询单个对象
- 查询集合: jt.query();
- 查询单个对象:jt.queryForObject(); 如果查询没结果就会报错,如果查询出来多个结果也会报错
friend类:
public class friend {
String name;
Integer money;
public void setName(String name) {
this.name = name;
}
public void setMoney(Integer money) {
this.money = money;
}
@Override
public String toString() {
return "friend{" +
"name='" + name + '\\'' +
", money=" + money +
'}';
}
}
主类:
ApplicationContext app = new ClassPathXmlApplicationContext("appOfDao.xml");
JdbcTemplate jt = app.getBean(JdbcTemplate.class);
String sql="SELECT * FROM account WHERE NAME=?";
//RowMapper: 每一条记录和javabean的属性和数据库里面一行记录进行映射
friend f=null;
f = jt.queryForObject(sql, new BeanPropertyRowMapper<friend>(friend.class), "张三");
System.out.println(f);
查询集合
ApplicationContext app = new ClassPathXmlApplicationContext("appOfDao.xml");
JdbcTemplate jt = app.getBean(JdbcTemplate.class);
String sql="SELECT * FROM account ";
//封装为List:集合里面的元素类型
List<friend> query = jt.query(sql, new BeanPropertyRowMapper<friend>(friend.class));
for(friend e:query)
{
System.out.println(e);
}
查询单条数据
ApplicationContext app = new ClassPathXmlApplicationContext("appOfDao.xml");
JdbcTemplate jt = app.getBean(JdbcTemplate.class);
String sql="SELECT MAX(money) FROM account";
//无论是返回单个数据还是单个对象,都是调用queryForObject
Integer moneyMax = jt.queryForObject(sql, Integer.class);
System.out.println("最高工资为:"+moneyMax);
使用带有具名参数的sql语句插入一条员工记录,并以Map的形式传入参数值
具名参数: (具有名字的参数,参数不是一个占位符了,而是以个变量名)
语法格式 --------------------> :参数名
需要使用spring的一个支持具名参数的springTemplate类
占位符参数: ?的顺序不能乱,传参的时候要注意
以map的形式传入参数
代码:
ApplicationContext app = new ClassPathXmlApplicationContext("appOfDao.xml");
JdbcTemplate jt = app.getBean(JdbcTemplate.class);
NamedParameterJdbcTemplate npjt = app.getBean(NamedParameterJdbcTemplate.class);
String sql="insert into account(name,money) values(:name,:money)";
//将有具名参数的值都放在map容器中
Map<String, Object> Map = new HashMap<String,Object>();
Map.put("name","大忽悠");
Map.put("money",8000);
int row = npjt.update(sql,Map);
System.out.println("影响的行数:"+row);
以SqlParameterSource的形式传入参数
使用该方法前,要确保自定义类中有get方法,因为该方法实现原理是从传入的对象中,找对象的get方法,去掉get,首字母小写,看得到的字符串是否和具名参数匹配.
ApplicationContext app = new ClassPathXmlApplicationContext("appOfDao.xml");
JdbcTemplate jt = app.getBean(JdbcTemplate.class);
NamedParameterJdbcTemplate npjt = app.getBean(NamedParameterJdbcTemplate.class);
String sql="insert into account(name,money) values(:name,:money)";
friend f=new friend();
f.setMoney(20000);
f.setName("小朋友");
int row = npjt.update(sql, new BeanPropertySqlParameterSource(f));
System.out.println("影响的行数"+row);
使用注解完成对JdbcTemplate的注入----小规模常用
test类:
@Component("test")
public class test {
@Autowired //按照类型注入
private JdbcTemplate jdbcTemplate;
int getJBDCTemplate(friend f)
{
int row = jdbcTemplate.update("insert into account values(?,?)", f.getName(), f.getMoney());
return row;
}
}
jdbc测试类:
ApplicationContext app = new ClassPathXmlApplicationContext("appOfDao.xml");
test t=(test)app.getBean("test");
friend f=new friend();
f.setName("超级大忽悠");
f.setMoney(40000);
int row = t.getJBDCTemplate(f);
System.out.println("影响的行数"+row);
配置文件:
<!--组件扫描-->
<context:component-scan base-package="com.jdbcTemplate"/>
<!--数据源对象-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--jdbc模板对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
声明式事务
数据库环境搭建—账户表,图书表,图书库存表
account账号表:
book图书表:
book_stock图书库存表:
jdbc.properties的配置文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/tx
jdbc.username=root
jdbc.password=126433
数据源配置并直接注入到jdbcTemplate中
<!--加载jdbc.properties-->
<!--引入context命名空间-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--组件扫描-->
<context:component-scan base-package="com.BookCheck"/>
<!--数据源对象-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--jdbc模板对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
Dao层和Service层的类环境搭建
BookDao类:
@Repository
public class BookDao {
@Autowired
private JdbcTemplate jdbcTemplate;
/*减去某个用户的剩余金额*/
public void updateBalance(String username,int price)
{
String sql="update account set money=money-? where name=?";
jdbcTemplate.update(sql,price,username);
}
/*获取某本图书的价格*/
public int getBookPrice(String isbn)
{
String sql="select price from book where ISBN=?";
return jdbcTemplate.queryForObject(sql, Integer.class,isbn);
}
/*减去某本书库存*/
public void updateStock(String isbn)
{
String sql="update book_stock set stock=stock-1 where isbn=?";
jdbcTemplate.update(sql,isbn);
}
}
Service类:
@Service
public class BookService {
@Autowired
BookDao bookDao;
/*结账*/
public void checkOut(String username,String isbn)
{
//1.减去库存
bookDao.updateStock(isbn);
//2.获取图书的价格
int bookPrice = bookDao.getBookPrice(isbn);
//3.减去余额
bookDao.updateBalance(username,bookPrice);
}
}
主类:
public class test {
static ApplicationContext ioc= new ClassPathXmlApplicationContext("appOfDao.xml");
public static void main(String[] args) {
如何根据纪元时间获得前半部分和后半部分('attempt updated_at' 列)