JavaJDBC详解——用Java连接数据库

JDBC是Java数据库连接的简称,是java语言操作数据库的一种方法

  • 步骤:

    1. 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
      1.复制mysql-connector-java-5.1.37-bin.jar到项目的libs目录下
      2.右键–>Add As Library

    2. 注册驱动

      //运用反射将驱动加载到类加载器中
      Class.forName("com.mysql.jdbc.Driver");
      
    3. 获取数据库连接对象 Connection

      conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root");
      
    4. 定义sql

    5. 获取执行sql语句的对象 Statement

      stmt = conn.createStatement();
      
    6. 执行sql,接受返回结果

      stmt.executeUpdate(sql);
      
    7. 处理结果

      while (resultSet.next()) {
                  int emp_id = resultSet.getInt("emp_id");
                  int dep_id = resultSet.getInt("dep_id");
                  String emp_name = resultSet.getString("emp_name");
                  String emp_sex = resultSet.getString("emp_sex");
                  int emp_age = resultSet.getInt("emp_age");
                  Date emp_onboard_date = resultSet.getDate("emp_onboard_date");
                  employeeDao.setEmp_id(emp_id);
                  employeeDao.setDep_id(dep_id);
                  employeeDao.setEmp_name(emp_name);
                  employeeDao.setEmp_sex(emp_sex);
                  employeeDao.setEmp_age(emp_age);
                  employeeDao.setEmp_onboard_date(emp_onboard_date);
                  System.out.println(employeeDao.toString());
              }
      
    8. 释放资源

      				connect.close();
                      statement.close();
                      resultSet.close();
      

对于JDBC事务管理的相关内容

事务是对一个包含多个步骤的业务操作,如果这个业务被事务管理那么,他们要么同时成功,要么同时失败。

事物的操作

  1. 开启事物

    connect.setAutoCommit(false)

  2. 提交事物

    connect.commit()

  3. 回滚事务

    connect.rollback()

脏读: 脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
例如:
张三的工资为5000,事务A中把他的工资改为8000,但事务A尚未提交。
与此同时,
事务B正在读取张三的工资,读取到张三的工资为8000。
随后,
事务A发生异常,而回滚了事务。张三的工资又回滚为5000。
最后,
事务B读取到的张三工资为8000的数据即为脏数据,事务B做了一次脏读。

不可重复读: 是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
例如:
在事务A中,读取到张三的工资为5000,操作没有完成,事务还没提交。
与此同时,
事务B把张三的工资改为8000,并提交了事务。
随后,
在事务A中,再次读取张三的工资,此时工资变为8000。在一个事务中前后两次读取的结果并不致,导致了不可重复读。

幻读: 是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
例如:
目前工资为5000的员工有10人,事务A读取所有工资为5000的人数为10人。
此时,
事务B插入一条工资也为5000的记录。
这是,事务A再次读取工资为5000的员工,记录为11人。此时产生了幻读。
在这里插入图片描述

数据库连接池

  1. 概念:本质上就是一个容器,用来存放数据库连接对象。当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。

  2. 实现

    1. 标准接口:DataSource javax.sql 包下的

      1. 方法:

        • 获取连接:getConnection()
        • 归还连接:Connection.close()。如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了。而是归还连接
      2. 数据库连接池的种类:

        1. C3P0:数据库连接池技术
        2. Druid:数据库连接池实现技术,由阿里巴巴提供
      3. C3P0:

        • 步骤:

          1. 导入jar包 (两个) c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar ,

            • 不要忘记导入数据库驱动jar包
          2. 定义配置文件:

            • 名称: c3p0.properties 或者 c3p0-config.xml

              c3p0-config.xml:
              <!-- 连接池参数 -->
              <property name="initialPoolSize">5</property><!--初始化申请连接对象-->
              <property name="maxPoolSize">10</property><!--最大申请连接对象-->
              <property name="checkoutTimeout">3000</property><!--超时时间-->
              
            • 路径:直接将文件放在src目录下即可。

          3. 创建核心对象 数据库连接池对象 ComboPooledDataSource

          4. 获取连接: getConnection

        • 代码:
          //1.创建数据库连接池对象
          DataSource ds = new ComboPooledDataSource();
          //2. 获取连接对象
          Connection conn = ds.getConnection();

问题1:利用数据库连接池工具类进行增删改操作时,出现DataSource对象出现空指针异常可能出现的一种情况:

​ 当DataSource对象提示空指针异常时可能出现在静态代码块再次重新定义了一个ds对象,导致类中的ds没有被赋值,出现空指针异常问题。
在这里插入图片描述

问题2:当定义实体类时一定要记住用引用数据类型,基本数据类型在进行BeanPropertyRowMapper对象创建时会无法读取null值

queryforobject方法用于聚合函数查询,query函数需要输入BeanPropertyRowMapper对象

  1. 调用JdbcTemplate的方法来完成CRUD的操作
    • update():执行DML语句。增、删、改语句
    • queryForMap():查询结果将结果集封装为map集合,将列名作为key,将值作为value 将这条记录封装为一个map集合
      • 注意:这个方法查询的结果集长度只能是1
    • queryForList():查询结果将结果集封装为list集合
      • 注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中
    • query():查询结果,将结果封装为JavaBean对象
      • query的参数:RowMapper
        • 一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装
        • new BeanPropertyRowMapper<类型>(类型.class)
    • queryForObject:查询结果,将结果封装为对象
      • 一般用于聚合函数的查询

Statement 和 PreparedStatement 有什么区别?

一、使用Statement而不是PreparedStatement对象
JDBC驱动的最佳化是基于使用的是什么功能. 选择PreparedStatement还是Statement取决于你要怎么使用它们. 对于只执行一次的SQL语句选择Statement是最好的. 相反, 如果SQL语句被多次执行选用PreparedStatement是最好的.

PreparedStatement的第一次执行消耗是很高的. 它的性能体现在后面的重复执行. 例如, 假设我使用Employee ID, 使用prepared的方式来执行一个针对Employee表的查询. JDBC驱动会发送一个网络请求到数据解析和优化这个查询. 而执行时会产生另一个网络请求. 在JDBC驱动中,减少网络通讯是最终的目的. 如果我的程序在运行期间只需要一次请求, 那么就使用Statement. 对于Statement, 同一个查询只会产生一次网络到数据库的通讯.

对于使用PreparedStatement池的情况下, 本指导原则有点复杂. 当使用PreparedStatement池时, 如果一个查询很特殊, 并且不太会再次执行到, 那么可以使用Statement. 如果一个查询很少会被执行,但连接池中的Statement池可能被再次执行, 那么请使用PreparedStatement. 在不是Statement池的同样情况下, 请使用Statement.

二、使用PreparedStatement的Batch功能
Update大量的数据时, 先Prepare一个INSERT语句再多次的执行, 会导致很多次的网络连接. 要减少JDBC的调用次数改善性能, 你可以使用PreparedStatement的AddBatch()方法一次性发送多个查询给数据库. 例如, 让我们来比较一下下面的例子.

例 1: 多次执行Prepared Statement

PreparedStatement ps = conn.prepareStatement(
  “INSERT into employees values (?, ?, ?));
for (n = 0; n < 100; n++) {
 ps.setString(name[n]);
 ps.setLong(id[n]);
 ps.setInt(salary[n]);
 ps.executeUpdate();
}

例 2: 使用Batch

PreparedStatement ps = conn.prepareStatement(
 “INSERT into employees values (?, ?, ?));
for (n = 0; n < 100; n++) {
 ps.setString(name[n]);
 ps.setLong(id[n]);
 ps.setInt(salary[n]);
 ps.addBatch();
}
ps.executeBatch();

在例 1中, PreparedStatement被用来多次执行INSERT语句. 在这里, 执行了100次INSERT操作, 共有101次网络往返. 其中,1次往返是预储statement, 另外100次往返执行每个迭代. 在例2中, 当在100次INSERT操作中使用addBatch()方法时, 只有两次网络往返. 1次往返是预储statement, 另一次是执行batch命令. 虽然Batch命令会用到更多的数据库的CPU周期, 但是通过减少网络往返,性能得到提高. 记住, JDBC的性能最大的增进是减少JDBC驱动与数据库之间的网络通讯.
注:Oracel 10G的JDBC Driver限制最大Batch size是16383条,如果addBatch超过这个限制,那么executeBatch时就会出现“无效的批值”(Invalid Batch Value) 异常。因此在如果使用的是Oracle10G,在此bug减少前,Batch size需要控制在一定的限度。

感谢您的阅读,如果本篇文章对您有帮助,欢迎点赞,关注,您的阅读是我莫大的鼓励!

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值