MySQL数据库之DJBC——day30 事务(转账问题),连接池(四种连接池)

编程入门 行业动态 更新时间:2024-10-06 23:28:30

MySQL数据库之DJBC——day30  事务(转账问题),<a href=https://www.elefans.com/category/jswz/34/1766187.html style=连接池(四种连接池)"/>

MySQL数据库之DJBC——day30 事务(转账问题),连接池(四种连接池)

这是数据库中学习的最清楚的一个小章节了,前面的内容还没有补上,在全程班开始的这几天的空挡争取补上,加油,大家都有了自己的目标,学的太晚,加油
批处理

批处理

插入大量的数据的时候建议用批处理
statement.addBatch();//添加批处理,先将数据进行缓存
statement.executeBatch();//执行批处理
statement.clearBatch();//清空缓存

JDBC调用存储过程和函数的自定义

调用存储过程 {call <procedure-name>[(<arg1>,<arg2>, ...)]}
Connection conn = JDBCUtils.getConnection();
String sql="{call testPro(?,?)}"; //输入或输出参数用?占位CallableStatement prepareCall = conn.prepareCall(sql);//给输入参数设置值prepareCall.setInt(1,7369);//如果有输出参数我们需要注册输出参数
prepareCall.registerOutParameter(2, Types.INTEGER);boolean b = prepareCall.execute();//获取输出结果int r = prepareCall.getInt(2);
System.out.println(r);
//释放资源
JDBCUtils.close(conn,prepareCall);
调用自定义函数 {?=call<procedure -name >[( < arg1 >,<arg2 >, ...)]}
String sql="{?=call testFun(?)}";CallableStatement callableStatement = conn.prepareCall(sql);//设置输入参数
callableStatement.setInt(2,7902);//注册返回值
callableStatement.registerOutParameter(1, Types.INTEGER);callableStatement.execute();
//获取返回的结果int r = callableStatement.getInt(1);
System.out.println("结果是:"+r);//释放资源
JDBCUtils.close(conn,callableStatement);

获取自增长的键值

要获取自增长键的值,需要在获取操作对象的时候声明一个参数
Statement.RETURN_GENERATED_KEYSPreparedStatement preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);2.当数据插入成功后,就可以取出这个自增长键的值//获取自增长键的结果集ResultSet generatedKeys = preparedStatement.getGeneratedKeys();while (generatedKeys.next()){keyValue = generatedKeys.getInt(1);}3.你在其他表中就可以使用这个自增长键的值           

事务

概念:

在一个事务中有多个逻辑单元组成,这些逻辑单元是一个整体,不可分割,要么都成功,要么都失败

事务的特性:
  • 原子性:不可分割,要么都发生,要么都不发生
  • 一致性:在同一个事务中同步进行,从一个一致性状态到另一个一致性状态
  • 持久性:只要进行提交或回滚就不能更改
  • 隔离性:多并发都需要隔离,数据库对每一个用户开启的事务不能被其他的事务进行干扰

案例一:
银行系统,张三给李四进行转钱
解决钱不翼而飞的情况

package org.westos.demo1shiwu;import org.westos.utils.JDBCUtils;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;/*** @Description:进行转账,出现异常的解决* @Author:@李小白* @Date:2019/8/29 10:47** 如果发生了这种钱不翼而飞的异常,我们应该意识到,我们应该把发钱收钱存到一个事务当中。* 解决:* 进行手动提交* 如果发生异常,我们回滚事务* 不管有没有遇见问题我们都要进行正常提交* 首先,我们不要抛出异常进行手动抓取,发现关闭资源引用不到向上提取* 然后我们再进行测试**/
public class JDBCDemo1 {public static void main(String[] args) {//张三给李四转钱Connection conn=null;PreparedStatement statement1=null;PreparedStatement statement2=null;try {//进行连接数据库conn = JDBCUtils.getConnection();//默认是自动提交//进行手动提交conn.setAutoCommit(false);//设置成手动提交//张三少钱String sql1="update bank set money=money-1000 where username='zhangsan'";statement1 = conn.prepareStatement(sql1);//执行statement1.executeUpdate();//制造错误//System.out.println(1/0);//李四多钱String sql2="update bank set money=money+1000 where username='lisi'";statement2 = conn.prepareStatement(sql2);statement2.executeUpdate();} catch (Exception e) {//如果遇见问题,我们就进行回滚try {conn.rollback();} catch (SQLException e1) {e1.printStackTrace();}e.printStackTrace();} finally {//不管有无异常我们都进行提交try {connmit();} catch (SQLException e) {e.printStackTrace();}//释放资源try {conn.close();statement1.close();statement2.close();} catch (SQLException e) {e.printStackTrace();}}}
}

案例二
银行系统转账,制造回滚点

package org.westos.demo1shiwu;import org.westos.utils.JDBCUtils;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Savepoint;/*** @Description:进行转账,设置回滚点* @Author:@李小白* @Date:2019/8/29 10:47** 分别两次进行转账* 第一次转账1000,第二次转账500,分别制造异常,发现只要有一个异常我们都转不过去* 第一次没有异常第二次遇到异常* 解决* 制造回滚点* 只要出现异常就回到回滚点**/
public class JDBCDemo2 {public static void main(String[] args) {//张三给李四转钱Connection conn=null;PreparedStatement statement1=null;PreparedStatement statement2=null;PreparedStatement statement3=null;PreparedStatement statement4=null;Savepoint savepoint=null;try {//进行连接数据库conn = JDBCUtils.getConnection();//进行手动提交conn.setAutoCommit(false);//第一次转账//张三少钱String sql1="update bank set money=money-1000 where username='zhangsan'";statement1 = conn.prepareStatement(sql1);//执行statement1.executeUpdate();//制造异常// System.out.println(1/0);//李四多钱String sql2="update bank set money=money+1000 where username='lisi'";statement2 = conn.prepareStatement(sql2);statement2.executeUpdate();//第二次转账savepoint = conn.setSavepoint();//张三少钱String sql3="update bank set money=money-500 where username='zhangsan'";statement3 = conn.prepareStatement(sql3);//执行statement3.executeUpdate();//制造异常System.out.println(1/0);//李四多钱String sql4="update bank set money=money+500 where username='lisi'";statement4 = conn.prepareStatement(sql4);statement4.executeUpdate();} catch (Exception e) {//如果遇见问题,我们就进行回滚try {
//                conn.rollback();//回滚事件conn.rollback(savepoint);//回滚到指定的回滚点} catch (SQLException e1) {e1.printStackTrace();}e.printStackTrace();} finally {//不管有无异常我们都进行提交try {connmit();} catch (SQLException e) {e.printStackTrace();}//释放资源try {conn.close();statement1.close();statement2.close();} catch (SQLException e) {e.printStackTrace();}}}
}
事务的隔离级别
如果不考虑隔离的话出现的读问题;
  • 脏读:在一个事务中读取到另一个事务没有提交的数据
  • 不可重复度:在一个事物中,每次读取的数据都不一样(针对update)
  • 虚读(幻读):在一个事物中两次查询的结果不一致(针对insert)无法演示,MySQL已经默认避免了
MySQL的四种隔离级别

read uncommitted 读未提交 上面的三种情况都会出现
read committed 读已提交 可以避免脏读的情况 Oracle默认级别
repeatable read 可重复度 可避免脏读和不可重复读 MySQL默认级别
serializable 串行化 可以避免所有的问题,,但是效率最低

演示:脏读的发生
zhangsan 给lisi 转钱

开启两个窗口进行演示,一个转钱一个收钱
mysql  -uroot    -p123456//登录数据库可以设置数据库的隔离级别,四种隔离级别分别设置
set session transaction isolation level read  uncommitted;开启事务 start transaction;
修改数据:udate   bank set money=1500 where username='lisi'第一种隔离级别
让另一个窗口也开启事务,进行查找数据,查到了就是脏读
zhangsan 一提交commit;  lisi又查不到了第二种隔离级别:
lisi每次查看的钱数都不一样第三种隔离级别:
lisi需要把卡退出来在进行查询,才能看到第四种隔离级别:
lisi需要提交再进行查询,才能看到java中控制隔离级别:(了解)Connection的apivoid setTransactionIsolation(int level) level是常量

常见连接池的使用

为什么会有连接池?
由于建立数据库资源是一种非常耗时耗资源的行为,在连接池中放一些连接,放在内存中,需要的时候在从连接池中直接申请,借完要还

DBCP连接池

DataBase Connection Poll数据库连接池
是Apache开发,通过连接池可以自动管理数据库的释放和断开

  • 使用步骤
    1.配置数据库一个JAR包和DBCP的两个JAR包(commons-dbcp-1.4.jar和commons-pool-1.5.6.jar)
    2.使用api
    a.配置文件编码
    a.硬编码(不推荐)

案例:
转账的硬编码和配置文件编码
BasicDataSource bs = new BasicDataSource();

package org.westos.demo2lianjiechi;import org.apachemons.dbcp.BasicDataSource;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;/*** @Description:常见的两种连接池之DBC的硬编码方式* @Author:@李小白* @Date:2019/8/30 16:36* DBCP的硬编码的方式首先导入JAR包* 然后就是创建数据源,导入Driver的名字和数据库的驱动和用户名和密码* 然后进行连接数据库,遍历结果集和关闭资源**/
public class DBCPDemo1 {public static void main(String[] args) throws SQLException {//依赖DBCP的两个jar包//创建数据源BasicDataSource bs = new BasicDataSource();bs.setDriverClassName("com.mysql.jdbc.Driver");bs.setUrl("jdbc:mysql://localhost:3306/mydb");bs.setUsername("root");bs.setPassword("123456");bs.setMaxWait(1000);//进行连接Connection conn= bs.getConnection();PreparedStatement statement = conn.prepareStatement("select * from user");ResultSet resultSet = statement.executeQuery();//遍历结果集while (resultSet.next()) {System.out.println(resultSet.getInt(1));System.out.println(resultSet.getString(2));}//释放资源conn.close();bs.close();statement.close();resultSet.close();}
}

配置文件编码

package org.westos.demo2lianjiechi;import org.apachemons.dbcp.BasicDataSourceFactory;import javax.sql.DataSource;
import java.io.FileReader;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;/*** @Description:DBPC文件配置* @Author:@李小白* @Date:2019/8/30 18:11*/
public class DBPCDemo2 {public static void main(String[] args) throws Exception {//把JDBC配置文件进行导入,和MySQL的驱动进行导入//建立工厂Properties properties = new Properties();properties.load(new FileReader("src/dbcp.properties"));DataSource dataSource = new BasicDataSourceFactory().createDataSource(properties);//与数据库进行连接Connection conn = dataSource.getConnection();PreparedStatement statement = conn.prepareStatement("select * from user");ResultSet resultSet = statement.executeQuery();//进行遍历while (resultSet.next()) {System.out.println(resultSet.getInt(1));System.out.println(resultSet.getString(2));}//关闭资源conn.close();statement.close();resultSet.close();}
}
C3P0

是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate、Spring等。

  • 使步骤
    1.导入jar包(c3p0-0.9.1.2.jar)
    2.使用api
    案例:
    硬编码和配置文件编码
    ComboPooledDataSource source = new ComboPooledDataSource();
package org.westos.demo2lianjiechi;import com.mchange.v2.c3p0.ComboPooledDataSource;import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;/*** @Description:C3P0硬编代码* @Author:@李小白* @Date:2019/8/30 18:25*/
public class C3P0Demo1 {public static void main(String[] args) throws PropertyVetoException, SQLException {//把数据库和C3P0的jar包进导入//创建数据源ComboPooledDataSource source = new ComboPooledDataSource();source.setDriverClass("com.mysql.jdbc.Driver");source.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");//查询的库名字source.setUser("root");source.setPassword("123456");//和数据库进行连接Connection conn = source.getConnection();PreparedStatement statement = conn.prepareStatement("select * from user ");ResultSet resultSet = statement.executeQuery();//遍历结果集while (resultSet.next()) {System.out.println(resultSet.getInt(1));System.out.println(resultSet.getString(2));}//关闭数据流conn.close();statement.close();resultSet.close();}
}

配置文件编码

要求1:配置文件的名称:c3p0.properties 或者 c3p0-config.xml
要求2:配置文件的路径:src下编码只需要一句话

new ComboPooledDataSource()//使用默认的配置
//可以切换xml配置文件中的标签 来加载不同的配置比如更换Orecal的数据库的配置
new ComboPooledDataSource(String configName)//使用命名的配置 若配置的名字找不到,使用默认的配置

package org.westos.demo2lianjiechi;import com.mchange.v2.c3p0.ComboPooledDataSource;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;/*** @Description:C3p0进行文件配置* @Author:@李小白* @Date:2019/8/30 18:45*/
public class c3p0Demo2 {public static void main(String[] args) throws SQLException {//导入C3P0的配置文件jar包和MySQL的驱动JAR包//方法一:完成了//方法二:如果使用xml文件的第二配置,就把xml文件第二配置的名称传过来,就完成了ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("MyConfig");//与数据库进行连接Connection conn = comboPooledDataSource.getConnection();PreparedStatement statement = conn.prepareStatement("select  * from USER ");ResultSet resultSet = statement.executeQuery();//遍历结果集while (resultSet.next()) {System.out.println(resultSet.getInt(1));System.out.println(resultSet.getString(2));}//释放资源conn.close();statement.close();resultSet.close();}
}
DBUtils

Commons DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,
使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能。

使用步骤:
1.导入jar包(commons-dbutils-1.4.jar)
2.创建一个queryrunner类
queryrunner作用:操作sql语句
构造方法:
new QueryRunner(Datasource ds);
3.编写sql
4.执行sql
query(…):执行r操作
update(…):执行cud操作

	使用步骤// 创建对象QueryRunner runner = new QueryRunner(new ComboPooledDataSource());// 定义sqlString sql = "insert into bank(username,money) values(?,?)";// 执行sqlrunner.update(sql,"赵六",500);....执行查询后返回的结果集ResultSetHandler:封装结果集 接口BeanListHandler, 将查询结果的每一条记录封装成指定的bean对象,将每一个bean对象放入list中 返回.

案例

package org.westos.demo2lianjiechi;import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.apachemons.dbutils.QueryRunner;
import org.apachemons.dbutils.handlers.BeanHandler;
import org.apachemons.dbutils.handlers.BeanListHandler;
import org.apachemons.dbutils.handlers.MapHandler;import javax.sql.DataSource;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Properties;/*** @Description:DBUtils:简化JDBC封装的开源工具* @Author:@李小白* @Date:2019/8/30 20:38*/
public class DuridDBUtilsDemo1 {public static void main(String[] args) throws Exception {//导入DBUtils的JAR包,和数据库的JAR包//创建德鲁伊的工厂类Properties properties = new Properties();properties.load(new FileReader("src/druid.properties"));DataSource ds = new DruidDataSourceFactory().createDataSource(properties);//创建QueryRunner 对象//传入数据源QueryRunner queryRunner = new QueryRunner(ds);//DML DQL返回值,你影响的行数int i = queryRunner.update("insert into user values(?,?)", 4, "李强娜");if (i>0) {System.out.println("插入成功");}else {System.out.println("插入失败");}//把你要查询的数据封装起来,//BeanListHandler,把数据库查出来的多条数据用对象封装气啦,再把对象放到集合里面List<User> query = queryRunner.query("select * from user", new BeanListHandler<User>(User.class));System.out.println(query);//查询一条结果把结果放到对象里面 BeanHandlerUser query1 = queryRunner.query("select * from user ", new BeanHandler<User>(User.class));System.out.println(query1);//MapHandler () 把查询的结果放到Map集合里面Map<String, Object> map = queryRunner.query("select * from user ", new MapHandler());System.out.println(map);Object id = map.get("id");System.out.println(id);Object username = map.get("username");System.out.println(username);System.out.println(map.size());}
}
package org.westos.demo2lianjiechi;/*** @Description:TODO* @Author:@李小白* @Date:2019/8/30 21:00*/
public class User {private  int id;private String name;public User() {}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +'}';}
}

德鲁伊连接池

package org.westos.demo2lianjiechi;import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;/*** @Description:连接池里面的德鲁伊连接池(DRUID),硬编码的方式* @Author:@李小白* @Date:2019/8/30 19:12*/
public class DruidDemo1 {public static void main(String[] args) throws SQLException {//德鲁伊连接池和DBCP连接池真的很像//导入德鲁伊连接池的JAR包和MySQL的jar包//创建数据源DruidDataSource ds = new DruidDataSource();ds.setDriverClassName("com.mysql.jdbc.Driver");ds.setUrl("jdbc:mysql:///mydb");ds.setUsername("root");ds.setPassword("123456");//和数据库建立连接DruidPooledConnection conn = ds.getConnection();PreparedStatement statement = conn.prepareStatement("select  * from user");ResultSet resultSet = statement.executeQuery();//遍历结果集while (resultSet.next()) {System.out.println(resultSet.getInt(1));System.out.println(resultSet.getString(2));}//释放资源conn.close();statement.close();resultSet.close();}
}
package org.westos.demo2lianjiechi;import com.alibaba.druid.pool.DruidDataSourceFactory;import javax.sql.DataSource;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;/*** @Description:德鲁伊的调用配置文件* @Author:@李小白* @Date:2019/8/30 19:32*/
public class DruidDemo2 {public static void main(String[] args) throws Exception {//导入德鲁伊的配置文件,jar包,MySQL的jar包//配置文件的方式Properties properties = new Properties();properties.load(new FileReader("src/druid.properties"));//用工厂类,创建一个数据源DataSource dataSource = new DruidDataSourceFactory().createDataSource(properties);//开始和数据库进行连接Connection conn = dataSource.getConnection();PreparedStatement statement = conn.prepareStatement("select * from user");ResultSet resultSet = statement.executeQuery();//遍历结果集while (resultSet.next()) {System.out.println(resultSet.getInt(1));System.out.println(resultSet.getString(2));}//释放资源conn.close();statement.close();resultSet.close();}
}

更多推荐

MySQL数据库之DJBC——day30 事务(转账问题),连接池(四种连接池)

本文发布于:2024-02-27 19:15:46,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1765920.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:连接池   四种   事务   数据库   MySQL

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!