学习JavaWeb第十天

学习JavaWeb第十天

JDBC事务
  • 事务的概念

    • 一组预编译的数据库语句,要么全部执行成功,要么全部执行失败
  • 事务的ACID四个原则(四个特性)

    • 原子性(atomicity)
      一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。
    • 一致性(consistency)
      事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。 状态一致
    • 隔离性(isolation)
      一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
    • 持久性(durability)
      持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。
      隔离级别

JDBC事务的操作

  • con.setAutoCommit(false) 自动提交
    • true
      自动提交
    • false
      手动提交

事务之间的隔离级别

  • Read uncommitted读未提交,就是一个事务可以读取另一个未提交事务的数据。
  • Read committed 读提交,就是一个事务要等另一个事务提交后才能读取数据。
  • Repeatable read 重复读(MySQL默认的级别),就是在开始读取数据(事务开启)时,不再允许修改操作
  • Serializable序列化 是最高的事务隔商级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数掘库性能,一般不使用。

出现的问题:
1.脏读:读取到错误的数据(在修改的情况)
2.不可以重复读取:两次读取到不同的数据(在修改的情况下)
3.幻读:两次读取到不同的数据(插入数据的条件下)

解决这些问题:就是让一个事务进行操作的时候,另一个事务不操作(互斥锁)

mysql的事务操作
事务的执行原理:只有commit之后才能把临时日志文件的数据提交到数据库里开启事务之后,都会先保存到临时日志文件里,rollback会进行日志的清空

-- mysql 数据默认是自动提交:默认为1
-- 修改为手动提交:
set autocommit=0
-- 开启事物:
start  transaction 
-- 提交事物:
commit
-- :回滚事务(最初的状态)
rollback
-- 设置回滚点:lm是回滚点的名称
savepoint lm; 
-- 回滚到具体的哪一步
rollback to lm;

mysql的事务操作(java)

  • setAutoCommit(false);
    开启事务
  • commit
    提交事务
  • rollback
    回滚事务

例子:

	/*
	 * // 描述 s q l 回滚过程,要么一并执行,要么一并不执行
	 */
	@Test // 单元测试模式
	public void describe() throws Exception {
		// 加载驱动
		Class.forName("com.mysql.jdbc.Driver");
		// 连接对象
		Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/day10", "root", "root");

		// 设置是否自动提交,手动提交false or 自动提交 true
		connection.setAutoCommit(false);
		// 模拟转账过程
		try {
			// 编写sql语句
			String sql = "update user set moeny = moeny-? where name =?";
			PreparedStatement prepareStatement = connection.prepareStatement(sql);
			// 设置占位符内容
			prepareStatement.setInt(1, 500);
			prepareStatement.setString(2, "李四");
			// 获取结果
			int update = prepareStatement.executeUpdate();
			System.out.println("修改的行数有" + update);

			// 模拟断电过程 发生异常
			int i = 1 / 0;

			// 编写sql语句
			String sql1 = "update ? set moeny = moeny+? where name =?";
			PreparedStatement prepareStatement1 = connection.prepareStatement(sql1);
			prepareStatement1.setInt(1, 500);
			prepareStatement1.setString(2, "张三");
			int update1 = prepareStatement1.executeUpdate();
			System.out.println("修改的行数有" + update1);

			// 手动提交
			connection.commit();
			// 关闭资源
			prepareStatement1.close();
			prepareStatement.close();
			connection.close();
		} catch (Exception e) {
			// sql语句不执行完整,sql语句回滚,表内容不变
			connection.rollback();
		}

	}

oracle&mysql事务

  • mysql事务默认是自动提交
  • oracle事务默认是手动提交
数据库连接池
  • 连接池产生的原因
    • 就是因为 每次对数据库进行CRUD操作都需要 获取连接,执行完操作后。都需要销毁连接 频繁的获取 和销毁连接资源 会造成大量的内存开销和影响程序的执行效率
  • 市面上常用的连接池有:1.dbcp 2.c3p0 3.阿里(druid)
    所有的连接池都是由厂商提供
    dbcp在apache下,是服务器 tomcat的内置连接池
    特点:dbcp速度快,但安全性低(可能会出现丢失数据)
    c3p0速度慢,但安全性高(重点)

关于配置文件的加载:

  • 方式1.
    使用类加载ClassLoader加载src的资源(固定写法)
    获得ClassLoader固定写法:当前类.class.getClassLoader().getResourceAsStream(“dbcp.properties”)
  • 方式2
    加载当前类同包下的资源,如果需要从src开始必须填写 “/”开头
    当前类 .class.getResourceAsStream("/jdbc.properties");
  • 方式3
    使用文件输入来读取
    FileInputStream inputStream = new FileInputStream(“src/dbcp.properties”);
    三大数据库连接池:DBCP、C3P0、Druid

DBCP使用步骤

  • DBCP连接池
    • 使用步骤:

    • 1、导入数据库驱动jar包、导入连接池jar包dbcp
      commons-dbcp-1.4.jar
      mysql-connector-java-5.1.40-bin.jar
      到lib文件目录下,并添加path

    • 2、定义配置文件:dbcp.properties

      • 放置到src文件夹目录下
    • 3、加载读取配置文件properties 使用反射读取配置文件时,配置文件需要与类放于同src目录下

    • 4、调用BasicDataSourceFactory的createDataSource(properties)方法读取配置文件,
      返回的是一个DataSource接口

    • 5、调用DataSource的getConnection()方法获取连接对象,返回的是Connection类对象

    • 6、编写sql语句

    • 7、创建数据库对象
      Statement createStatement = con.createStatement();
      创建查询语句 ResultSet executeQuery = createStatement.executeQuery(sql);
      或者
      PreparedStatement prepareStatement = con.prepareStatement(sql);

    • 8、返回的是结果集或受影响的行数
      ResultSet executeQuery = createStatement.executeQuery(sql);
      或者
      ResultSet resultSet = prepareStatement.executeQuery();

    • 9、关闭资源 ResultSet PreparedStatement
      Connection的不用关闭

dbcp.properties 文件:

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///day10
username=root
password=root
initialSize=6
maxActive=6

代码示例:

	@Test
	public void select() throws Exception {
		FileInputStream inputStream = new FileInputStream("src/dbcp.properties"); 
//		InputStream inputStream=TestDBCP.class.getClassLoader().getResourceAsStream("dbcp.properties");
//		InputStream inputStream = TestDBCP.class.getResourceAsStream("/dbcp.properties");
		Properties properties=new Properties();
		properties.load(inputStream);
		DataSource dataSource = BasicDataSourceFactory.createDataSource(properties);
		Connection connection = dataSource.getConnection();
		connection.setAutoCommit(false);
		String sql = "select * from user";
		PreparedStatement prepareStatement = connection.prepareStatement(sql);
		ResultSet query = prepareStatement.executeQuery();
		while (query.next()) {
			String name = query.getString("name");
			int id = query.getInt("id");
			double moeny = query.getDouble("moeny");
			System.out.println(name+"\t"+id+"\t"+moeny);
		}
		connection.commit();
		query.close();
		prepareStatement.close();
		prepareStatement.close();
	}

.
C3P0使用步骤
C3P0连接池

  • 使用C3P0连接池示例步骤
    • 1、导入数据库驱动jar包、导入连接池jar包C3P0
      mysql-connector-java-5.1.40-bin.jar
      c3p0-0.9.2.1.jar

    • 2、配置C3P0文件:

      • 第一种格式:c3p0.properties
      • 第二种格式:c3p0-config.xml
    • 3、调用ComboPooledDataSource的 构造方法 (properties)读取配置文件,
      无参构造是默认读取c3p0.properties文件或者是 c3p0-config.xml文件
      有参构造是读取自定义的c3p0-config.xml文件下选定的内容
      返回的是一个ComboPooledDataSource 对象

    • 4、调用ComboPooledDataSource的getConnection()方法获得连接对象
      返回的是Connection类对象

    • 5、编写 sql 语句

    • 6、创建数据库对象
      Statement createStatement = con.createStatement();
      创建查询语句 ResultSet executeQuery = createStatement.executeQuery(sql);
      或者
      PreparedStatement prepareStatement = con.prepareStatement(sql);

    • 7、返回的是结果集或受影响的行数
      ResultSet executeQuery = createStatement.executeQuery(sql);
      或者
      ResultSet resultSet = prepareStatement.executeQuery();

    • 8、关闭资源 ResultSet PreparedStatement
      Connection的不用关闭

配置C3P0文件,
c3p0.properties文件:

#c3p0
c3p0.driverClass=com.mysql.jdbc.Driver 
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/test0820?useUnicode=true&characterEncoding=utf-8
c3p0.user=root 
c3p0.password=root
c3p0.acquireIncrement=3 
c3p0.idleConnectionTestPeriod=60 
c3p0.initialPoolSize=10 
c3p0.maxIdleTime=60 
c3p0.maxPoolSize=150 
c3p0.maxStatements=100 
c3p0.minPoolSize=5

c3p0-config.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
	<default-config>
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql:///day08</property>
		<property name="user">root</property>
		<property name="password">root</property>
		
		<property name="initialPoolSize">10</property>
		<property name="maxIdleTime">30</property>
		<property name="maxPoolSize">20</property>
		<property name="minPoolSize">5</property>
		<property name="maxStatements">200</property>
	</default-config>
	
	<named-config name="mysql">
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql:///day10</property>
		<property name="user">root</property>
		<property name="password">root</property>
		
		<property name="initialPoolSize">10</property>
		<property name="maxIdleTime">30</property>
		<property name="maxPoolSize">20</property>
		<property name="minPoolSize">5</property>
		<property name="maxStatements">200</property>
	</named-config>
	
	<named-config name="oracle">
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql:///day08</property>
		<property name="user">root</property>
		<property name="password">root</property>
		
		<property name="initialPoolSize">10</property>
		<property name="maxIdleTime">30</property>
		<property name="maxPoolSize">20</property>
		<property name="minPoolSize">5</property>
		<property name="maxStatements">200</property>
	</named-config> 
</c3p0-config>

代码示例:

	@Test
	public void select() throws Exception {
		ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("mysql");
		Connection connection = comboPooledDataSource.getConnection();
		connection.setAutoCommit(false);
		String sql = "select * from user";
		PreparedStatement prepareStatement = connection.prepareStatement(sql);
		ResultSet query = prepareStatement.executeQuery();
		while (query.next()) {
			int id = query.getInt("id");
			String name = query.getString("name");
			double moeny = query.getDouble("moeny");
			System.out.println(id+"\t"+name+"\t"+moeny);
		}
		query.close();
		prepareStatement.close();
	}

Durid使用步骤
Durid连接池

  • 使用步骤:
    • 1、导包druid连接池jar包和导入数据库驱动jar包
      druid-1.0.9.jar
      mysql-connector-java-5.1.40-bin.jar

    • 2、配置durid配置文件,配置properties 加载properties

    • 3、调用DruidDataSourceFactory的createDataSource(properties),读取properties,返回的是DataSource对象

    • 4、调用DataSource的getConnection()方法
      返回的是Connection类对象

    • 5、编写 sql 语句

    • 6、创建数据库对象
      Statement createStatement = con.createStatement();
      创建查询语句 createStatement.executeQuery(sql);
      或者
      PreparedStatement prepareStatement = con.prepareStatement(sql);

    • 7、返回的是结果集或受影响的行数
      ResultSet executeQuery = createStatement.executeQuery(sql);
      或者
      ResultSet resultSet = prepareStatement.executeQuery();

    • 8、关闭资源 ResultSet PreparedStatement
      Connection的不用关闭
      代码示例:

	@Test
	public void alter() throws Exception {
		Properties properties = new Properties();
		InputStream inputStream = TestDurid.class.getClassLoader().getResourceAsStream("durid.properties");
		properties.load(inputStream);
		DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
		Connection connection = dataSource.getConnection();
		String sql = "update user set moeny=8888 where id=?";
		PreparedStatement prepareStatement = connection.prepareStatement(sql);
 		prepareStatement.setInt(1, 3);
		int update = prepareStatement.executeUpdate();
		prepareStatement.close();
		System.out.println("受影响的行数有:"+update);
	}

DBUtils工具(框架)

  • 概述
    传统JDBC开发过程中,无论是增删该数据,还是查询数据都特别麻烦,如果使用连接池就更加麻烦,所以DBUTILS这个工具目的就是简化CRUD操作。

    • 一般用于单张表操作,用于多张表操作过于复杂。
  • DML 数据操纵语言,表中数据的增删改

本类为测试dbutils类

  • 使用步骤:
    1、导入jar包 dbutils 驱动包 c3p0连接池jar包。
    比如:C3p0 c3p0-0.9.2.1.jar
    mysql-connector-java-5.1.40-bin.jar
    commons-dbutils-1.4.jar
    2、从连接池里面获取dataSource:,new ComboPooledDataSource()
    3、调用QueryRunner的有参构造方法new QueryRunner(dataSource)
    4、调用queryRunner的方法 查询方法:query() 修改的方法:update()

QueryRunner:核心对象,提供了一些增加、删除、修改、查询的方法

  • 增加、删除、修改的方法:qr.update()
    • 第一个参数:连接对象(可有可无)
    • 第二个参数:sql语句
    • 第三个参数:占位符的值
  • 查询的方法:qr.query()
    • 查询:第一个参数是sql 语句,
    • 第二参数BeanListHandler(User.class),
    • 表示返回的是一个结果集,就是集合,
    • 这个集合的泛型对应的就是其类名(列名与属性名都必须一样(通过反射来查找对应的属性)

查询

  • 探索结果集 返回对象的,需要定义于表中变量一样名称的字段及其类型
    • 多个对象记录 BeanListHandler 返回的是List 返回多个对象
    • 多个对象 ArrayListHandler 返回的是List<Object[]>
    • 单个对象 BeanHandler 返回的是第一行数据, 把第一行数据封装成了一个map对象
    • 单个对象 ArrayHandler 返回的是数组Object[] 无论数据多少、只返回第一行
    • 统计条数 ScalarHandler 返回的总记录数。注意点:一定要先使用long类型接收,再进行转化
    • 查询某列 ColumnListHandler 返回的是List 返回的是具体的一列,需要指明那一列
    • 单个对象 MapHandler 返回的是Map<String, Object> map的键就是 数据库列名称 值就是 列对应的内容
    • 多行对象记录 MapListHandler 把每一行封装成一个map对象 这个适用于查询所有对象
修改
  • int row = queryRunner.update(sql,4);
    返回的是受影响的行数

代码示例:

//new BeanListHandler<User>(User.class) 返回的是一个存储对象的集合List
	@Test
	public void queryBeanList() throws Exception {
		ComboPooledDataSource dataSource = new ComboPooledDataSource("mysql");
		QueryRunner queryRunner = new QueryRunner(dataSource);
		String sql="select * from user";
		List<User> query = queryRunner.query(sql, new BeanListHandler<User>(User.class));
		for (User user : query) {
			System.out.println(user);
		}
	}
	
	//  new BeanHandler<User>(User.class) 返回的是一个 是单个对象 如果有多个对象也只会返回第一个对象
	@Test
	public void queryBean() throws Exception {
		ComboPooledDataSource dataSource = new ComboPooledDataSource("mysql");
		QueryRunner queryRunner = new QueryRunner(dataSource);
		String sql="select * from user where id=?";
		User query = queryRunner.query(sql, new BeanHandler<User>(User.class),3);
		System.out.println(query);
	}
	
	//new ArrayListHandler() 返回的是一个存储数组对象的集合
	@Test
	public void queryArrayList()  throws Exception  {
		ComboPooledDataSource dataSource = new ComboPooledDataSource("mysql");
		QueryRunner queryRunner = new QueryRunner(dataSource);
		String sql="select * from user";
		List<Object[]> query = queryRunner.query(sql, new ArrayListHandler());
		for (Object[] objects : query) {
			System.out.println(Arrays.toString(objects));
		}
		
	}
	//new ArrayHandler() 返回的是一个对象数组 但无论数据多少、只返回第一行
	@Test
	public void queryArray() throws Exception {
		ComboPooledDataSource dataSource = new ComboPooledDataSource("mysql");
		QueryRunner queryRunner = new QueryRunner(dataSource);
		String sql="select * from user";
		Object[] query = queryRunner.query(sql, new ArrayHandler());
		System.out.println(Arrays.toString(query));
	}
	//new ScalarHandler() 返回的是一个总记录条数,sql语句需要改为统计条数的语句
	@Test
	public void queryScalar() throws Exception {
		ComboPooledDataSource dataSource = new ComboPooledDataSource("mysql");
		QueryRunner queryRunner = new QueryRunner(dataSource);
		String sql="select count(*) from user";
		Long query =(Long) queryRunner.query(sql, new ScalarHandler());
		System.out.println(query.intValue());
	}
	//new ColumnListHandler("name")  返回的是具体的一列,需要指明那一列
	@Test
	public void queryColumnList() throws Exception {
		ComboPooledDataSource dataSource = new ComboPooledDataSource("mysql");
		QueryRunner queryRunner = new QueryRunner(dataSource);
		String sql="select * from user";
		List<Object> query = queryRunner.query(sql, new ColumnListHandler("moeny"));
		for (Object object : query) {
			System.out.println(object);
		}
	}
	
	//new MapListHandler() 返回的是所有对象装载着Map集合的List集合 ,需要遍历,Map集合里面装载着所有对象Object
	@Test
	public void queryMapList() throws Exception {
		ComboPooledDataSource dataSource = new ComboPooledDataSource("mysql");
		QueryRunner queryRunner = new QueryRunner(dataSource);
		String sql="select * from user";
		List<Map<String,Object>> query = queryRunner.query(sql, new MapListHandler());
		/*
		 * for (Map<String, Object> map : query) { Set<String> keySet = map.keySet();
		 * for(String set :keySet) { System.out.println(map.get(set)); }
		 * 
		 * }
		 */
		for (Map<String, Object> map : query) {
			Set<Entry<String,Object>> entrySet = map.entrySet();
			for(Entry<String,Object> entry :entrySet) {
				System.out.println(entry.getKey()+"\t"+entry.getValue());
			}
		}
	}
	//new MapHandler() 返回的是一个对象的Map集合,需要遍历,而且顺序不一样 遇到多个对象也只会返回一个对象的Map集合
	@Test
	public void queryMap() throws Exception {
		ComboPooledDataSource dataSource = new ComboPooledDataSource("mysql");
		QueryRunner queryRunner = new QueryRunner(dataSource);
		String sql="select * from user";
		Map<String, Object> query = queryRunner.query(sql, new MapHandler());
		Set<Entry<String,Object>> entrySet = query.entrySet();
		for (Entry<String, Object> entry : entrySet) {
			System.out.println(entry.getKey()+"\t"+entry.getValue());
		}
	}
	
	//queryRunner.update(sql,88,2); 第一个为sql语句,第二个及以后的为占位符内容
	@Test
	public void update() throws Exception {
		ComboPooledDataSource dataSource = new ComboPooledDataSource("mysql");
		QueryRunner queryRunner = new QueryRunner(dataSource);
		/*
		 * 增加
		 * String sql = "insert into user values(?,?,?),(?,?,?)"; int update =
		 * queryRunner.update(sql,4,"老刘",3000,6,"老毛",2322);
		 */
		  String sql = "delete from user where id=?"; 
		  int update = queryRunner.update(sql,4);
		/*
		 *	 修改
		 * String sql = "update user set moeny=? where id=?"; int update =
		 * queryRunner.update(sql,88,2);
		 */
		System.out.println("受影响的行数有:"+update);
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值