JDBC事务控制:
1. 什么是事务:一个包含多个步骤或者业务操作.如果这个业务或者多个步骤被事务管理则这多个步骤要么同时成功,要么回滚(多个步骤同时执行失败),这多个步骤是整体不可分割的.
2. 操作:
开启事务:mysql--->strat transaction
提交事务:commit
回滚事务:rollback
3.使用Connection对象来管理事务
开启事务:setAutoCommit(boolean autoCommit):执行该方法里面传入的false值,手动开启事务,在执行sql语句之前开启事务
提交事务:commit();---->当所有的sql语句执行完毕才提交事务
回滚事务:rollback();--->当事务中发生异常时回滚事务,放在catch语句
4 . 示例:以银行转账为例:让张三给李四转账10000元
package com.crazy.transaction;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.crazy.tools.DBUtil;
public class TransfromTeat {
public static void main(String[] args) {
transfrom01();
//transfrom02();
}
// 含有事务的转账
public static void transfrom02() {
// 让张三给李四转账10000
// 首先让张三的钱减少
// 然后让李四的钱增加10000;
PreparedStatement pStatement = null;
PreparedStatement pStatement1 = null;
double money = 10000;
String username1 = "张三";
String username2 = "李四";
String sql = "update account set balance=balance-? where username =?";
String sql2 = "update account set balance=balance+? where username =?";
Connection connection = DBUtil.getConnection();
try {
connection.setAutoCommit(false);
// 通过connection连接获取预处理对象 让张三的钱减少10000
pStatement = connection.prepareStatement(sql);
pStatement.setDouble(1, money);
pStatement.setString(2, username1);
// 执行sql语句
int count = pStatement.executeUpdate();
// 手动制造异常
// int i=1/0;
// 李四增加10000
pStatement1 = connection.prepareStatement(sql2);
pStatement1.setDouble(1, money);
pStatement1.setString(2, username2);
// 执行sql语句
int count2 = pStatement1.executeUpdate();
System.out.println("转账成功");
} catch (Exception e) {
try {
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
System.out.println("转账失败");
e.printStackTrace();
} finally {
try {
pStatement.close();
} catch (SQLException e1) {
e1.printStackTrace();
}
try {
pStatement1.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// 不带事务的转账
public static void transfrom01() {
// 让张三给李四转账10000
// 首先让张三的钱减少
// 然后让李四的钱增加10000;
double money = 10000;
String username1 = "张三";
String username2 = "李四";
String sql = "update account set balance=balance-? where username =?";
String sql2 = "update account set balance=balance+? where username =?";
// 张三减少10000
int count = DBUtil.update(sql2, new Object[] { money, username1 });
int i = 1 / 0;
int count2 = DBUtil.update(sql2, new Object[] { money, username2 });
if (count > 0 && count2 > 0) {
System.out.println("成功");
} else {
System.out.println("失败");
}
DBUtil.closeAll();
}
}
连接池概念:
1.什么是连接池:其实就是一个容器,在这个容器当中存放着多个连接对象.
当系统开始运行时,可以让系统提前创建多个连接对象,放到容器中(连接池),当客户端需要连接对象时可以从连接池中申请一个连接,去访问数据库,当该链接使用完毕时,不再释放归还给系统,而是把这个链接对象归还给连接池
2.好处:
可以大大节省系统开销
可以提高访问速度
3.实现操作:
javax.sql 连接池
JNDI ---->Java Naming and Directory Interface Java命名和目录接口
使用JNDI降低程序和数据库的耦合度,使你的程序更加方便配置
是JavaEE规范中的重要标识规范之一,是EJB相关知识
将大量暴露在外部的代码放入DataSource,通过它来管理控制.
DataSource接口,它里面并不提供具体的实现,而是由驱动程序供应商(数据库厂商)提供
c3p0连接池:他是数据库连接池的一套技术
druid:也是一套数据库连接池的技术,由阿里巴巴提供的。
c3p0:数据库连接池技术
步骤:1.去网上下载两个jar包,分别是c3p0-0.9.5.2.jar和mchange-commons-java-0.2.12.jar
2.植入到工程的classpath类路径下,不要忘记导入MySQL驱动jar包,mysql-connector-java.jar
3.定义配置文件:
文件类型:c3p0.properties 或者 c3p0-config.xml
路径:放到classpath类路径下,(build--classes文件夹下,)对于工程来说直接放到src下面即可
4.获取DataSource对象:数据库连接池对象,通过实例化ComboPooledDataSource来获取
5.从连接池中获取连接对象,getConnection();
Driud:德鲁伊连接池技术
步骤:1.去官网下载jar包,--->druid-1.0.9.jar
2.定义配置文件:使用properties文件类型的,名字随便起
3.手动加载配置文件信息:Properties集合
4.获取DataSource对象:通过工厂方式来实现的,DruidDataSourceFactory
5.从连接池中获取连接对象,getConnection()
JDBC Template:
Spring框架提供了对JDBC简单的操作封装,使用JDBCTemplate对应来简化JDBC开发流程
步骤:1.官网下载对应的spring-JDBC相应的jar包导入到工程类路径下,放到lib文件下即可
2.创建JDBCTemplate对象,需要依赖于DataSource连接池(数据源)
3.使用JDBCTemplate对象中的api方法实现crud操作
3.1 DML操作:update()
3.2 DQL操作:查询 不用select 使用query
3.2.1 query():将查询的结果集封装成JavaBean对象
query()方法的参数:RowMapper
手动装配:使用匿名内部类,自定义装配查询的每条记录值
自动装配:使用Spring提供的BeanPropertyRowMapper实现类,完成数据的自动装配
具体操作--》new BeanPropertyRowMapper<类型>(类型.class)
3.2.2 queryForMap():将查询的结果集封装成map集合,只能封装一条记录:键key是字段,值value是字段值,结果集记录数只能是1;
3.2.3 queryForList():将结果集封装成List集合,在List集合中由多条记录,每一条记录都是一个map集合 List<Map<Object,Object>> list;
3.2.4 queryForObject():将结果集封装成一个对象,一般用于聚合函数查询总记录数int count()
具体操作:
//增删改操作
//修改数据
public static void modifyData(){
int count = jdbcTemplate.update("update account set username = ? where username =?","小五","王五");
System.out.println(count);
}
//删除数据
public static void deleteData(){
System.out.println(jdbcTemplate.update("delete from account where username=?","小五"));
}
//插入数据
public static void insertData(){
System.out.println(jdbcTemplate.update("insert into account values(null,?,?)","王五",5000));
}
public static void test(){
//查询张三的这条信息 封装到账户对象中
String username = "张三";
String sql="select * from account where username = ?";
Map<String ,Object> map=jdbcTemplate.queryForMap(sql,username);
System.out.println(map);//{id=1,username=张三,balance=20000.0}
}
//简化手动封装的方法
public static void queryAll(){
String sql="select * from account";
List<Map<String,Object>> list = jdbcTemplate.queryForList(sql);
System.out.println(list);
}
//使用query方法优化queryBean方法
public static void queryBean2(){
List<Account> list = jdbcTemplate .query("select * from account ",new
BeanPropertyRowMapper<Account>(Account.class));
System.out.println(list);
}
//将查询的结果集封装到JavaBean对象
public static void queryBean(){
String sql = "select * from account where username ='张三'";
//RowMapper<T>
List<Account> list =jdbcTemplate.query(sql,new RowMapper<Account>(){
@Override
public Account mapRow(ResultSet set ,int arg1) throws SQLException{
//封装查询到的每一条记录值
Account account =new Account();
int id=set.getInt(1);
String username = set.getString(2);
double balance=set.getDouble(3);
account.setId(id);
account.setUsername(username);
account.setBalance(balance);
return account;
}
});
System.out.println(list);//[Account [id=1,username=张三,balance=20000.0]]
}
//查询总记录 查询account表中的所有的记录数
public static void queryTotalNum(){
//queryFoObject()
Integer count jdbcTemplate.queryForObject("select count(*) from account",Integer.class);
System.out.println(count);//4
}