properties配置文件:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test1
jdbc.username=root
jdbc.password=126433
<!--加载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);
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);
具名参数: (具有名字的参数,参数不是一个占位符了,而是以个变量名)
语法格式 --------------------> :参数名
需要使用spring的一个支持具名参数的springTemplate类
占位符参数: ?的顺序不能乱,传参的时候要注意
代码:
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);
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);
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.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/tx
jdbc.username=root
jdbc.password=126433
<!--加载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>
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) {
BookService bs = ioc.getBean(BookService.class);
bs.checkOut("大忽悠","ISBN_001");
System.out.println("结账成功");
}
}
Spring只是个容器,因此它并不做任何事务的具体实现。他只是提供了事务管理的接口PlatformTransactionManager,具体内容由就由各个事务管理器来实现。
事务管理器可以在目标方法运行前后进行事务控制
目前使用DataSourceTransactionManager
<!--创建事务管理器对象-->
<!--需要导入aspectj的坐标,即面向切面编程的坐标-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--操作事务需要连接对象,连接对象在连接池中(数据源)-->
<!--控制数据源,通过操作connection连接,来进行事务的回滚,自动提交操作-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--开启基于注解的事务控制模式,依赖tx命名空间-->
<tx:annotation-driven transaction-manager="transactionManager"/>
@Transactional(timeout = 3)
public void checkOut(String username,String isbn)
{
//1.减去库存
bookDao.updateStock(isbn);
//2.获取图书的价格
int bookPrice = bookDao.getBookPrice(isbn);
//3.减去余额
bookDao.updateBalance(username,bookPrice);
}
/*结账*/
@Transactional(readOnly = false)
public void checkOut(String username,String isbn)
{
//1.减去库存
bookDao.updateStock(isbn);
//2.获取图书的价格
int bookPrice = bookDao.getBookPrice(isbn);
//3.减去余额
bookDao.updateBalance(username,bookPrice);
}
可以让原来默认回滚的异常给它不回滚
@Transactional(noRollbackFor ={ArithmeticException.class,NullPointerException.class} )
//数学异常不回滚,空指针异常不回滚
public void checkOut(String username,String isbn)
{
//1.减去库存
bookDao.updateStock(isbn);
//2.获取图书的价格
int bookPrice = bookDao.getBookPrice(isbn);
//3.减去余额
bookDao.updateBalance(username,bookPrice);
}
原本不回滚的异常指定让其回滚,原本编译时异常不会回滚
@Transactional(rollbackFor = {FileNotFoundException.class})
//文件异常回滚
public void checkOut(String username,String isbn)
{
//1.减去库存
bookDao.updateStock(isbn);
//2.获取图书的价格
int bookPrice = bookDao.getBookPrice(isbn);
//3.减去余额
bookDao.updateBalance(username,bookPrice);
}
例如:
set [session|global] transaction isolation level read uncommitted
如果有多个事务同时进行嵌套运行,子事务是否要和大事务共同用一个事务
@Repository
public class BookDao {
@Autowired
private JdbcTemplate jdbcTemplate;
/*减去某个用户的剩余金额*/
@Transactional(propagation = Propagation.REQUIRES_NEW)
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);
}
/*减去某本书库存*/
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateStock(String isbn)
{
String sql="update book_stock set stock=stock-1 where isbn=?";
jdbcTemplate.update(sql,isbn);
}
}
@Transactional(propagation = Propagation.REQUIRED)
//文件异常回滚
public void checkOut(String username,String isbn)
{
//1.减去库存
bookDao.updateStock(isbn);
//2.获取图书的价格
int bookPrice = bookDao.getBookPrice(isbn);
//3.减去余额
bookDao.updateBalance(username,bookPrice);
}
@Transactional
@Service
public class BookService {
@Autowired
BookDao bookDao;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void checkOut(String username,String isbn)
{
//1.减去库存
bookDao.updateStock(isbn);
//2.获取图书的价格
int bookPrice = bookDao.getBookPrice(isbn);
//3.减去余额
bookDao.updateBalance(username,bookPrice);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateStock(String isbn)
{
bookDao.updateStock(isbn);
}
@Transactional
void testmain()
{
checkOut("大忽悠","ISBN_001");
updateStock("ISBN_002");
System.out.println("结账成功");
int i=10/0;
}
}
主类:
public static void main(String[] args) {
ApplicationContext ioc= new ClassPathXmlApplicationContext("appOfDao.xml");
BookService bs = ioc.getBean(BookService.class);
//虽然testmain里面的两个方法都开了新车,
//但是testmain方法最后出现了异常,效果并不如预期般改变(即回滚了事务)
bs.testmain();
}
原因:代理对象调用方法的时候,才能实现事务的控制
无法进行事务控制,也就相当于无法通过动态代理,对方法进行增强的操作,无法进行增强的操作,当然也就无法进行事务控制了
死循环原因: IOC容器创建时,先去实例化BookService对象,实例化BookService时,发现需要给其成员变量bookService装配对象,为了给成员变量装配对象,会去容器中找对应类型的对象,结果找到了还没创建的对象BookService对象(还没创建是因为正在为其成员变量赋值),于是又去给他创建对象…
<!--导入aspectj的坐标-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.4</version>
</dependency>
<!--导入spring的坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<!--引入Spring测试坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<!--junit坐标-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
</dependency>
<!--mysql驱动的坐标-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
<!--c3p0数据库连接池的坐标-->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!--druid数据库连接池坐标-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--spring jdbc的坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<!--spring tx的坐标,处理事务的-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<!--组件扫描-->
<context:component-scan base-package="com.BookCheck"/>
<!--加载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>
<!--配置平台事务管理器-->
<!--需要导入aspectj的坐标,即面向切面编程的坐标-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--获取数据库连接池对象-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--通知:事务增强
transaction-manager="transactionManager":指定配置的是哪一个事务管理器
-->
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<!--事务属性-->
<tx:attributes>
<!--指名哪个方法是事务方法: 切入点表达式只是说,事务管理器要切入这些方法,
哪些方法要加事务使用tx:method指定-->
<tx:method name="*"/><!--所有方法都加上事务管理-->
<!-- -1代表用于不会超时-->
<tx:method name="checkOut" propagation="REQUIRED" timeout="-1"></tx:method>
<tx:method name="check*"></tx:method>
<!--所有以get开头的方法,都设置为只读,加快速度-->
<tx:method name="get*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!--配置事务的aop织入-->
<aop:config>
<!--切点表达式的抽取-->
<aop:pointcut id="txPoint" expression="execution(* com.BookCheck.Service.BookService.*(..))"/>
<!--事务建议:事务增强-->
<aop:advisor advice-ref="myAdvice" pointcut-ref="txPoint"/>
</aop:config>