JDBC阶段学习二

JDBC阶段学习二

今日内容

1 PreparedStatement
2 JDBC事务的处理
3 数据库连接池
4 c3p0数据库连接池技术
5 Druid

PreparedStatement

为甚么要使用PreparedStatement

理由主要是两点:
(1)、使用statement进行sql操作的时候,每次读取到sql语句都会发送给MySQL数据库进行编译,但是使用PreparedStatement时,会先将sql语句发送给数据库进行预编译,然后PreparedStatement对象引用这个预编译,然后将参数多次传给PreparedStatement对象并执行,总而言之PreparedStatement因为有预先编译的功能,提高 SQL 的执行效率。
(2)、可以有效的防止 SQL 注入的问题,安全性更高。

如何使用PreparedStatement

  1. 编写 SQL 语句,未知内容使用?占位:“SELECT * FROM user WHERE name=? AND password=?”;
  2. 获得 PreparedStatement 对象
  3. 设置实际参数:setXxx(占位符的位置, 真实的值)
  4. 执行参数化 SQL 语句
  5. 关闭资源

connection创建PreparedStatement对象在这里插入图片描述
PreparedStatement 接口中的方法:
在这里插入图片描述
PreParedStatement设置参数的方法
在这里插入图片描述

PreparedStatement的使用示例

public class Demo8Login {
 //从控制台上输入的用户名和密码
 public static void main(String[] args) throws SQLException {
 Scanner sc = new Scanner(System.in);
 System.out.println("请输入用户名:");
 String name = sc.nextLine();
 System.out.println("请输入密码:");
 String password = sc.nextLine();
 login(name, password);
 }
 /**
 * 登录的方法
 * @param name
17 / 21 
 * @param password
 */
 private static void login(String name, String password) throws SQLException {
 Connection connection = JdbcUtils.getConnection();
 //写成登录 SQL 语句,没有单引号
 String sql = "select * from user where name=? and password=?";
 //得到语句对象
 PreparedStatement ps = connection.prepareStatement(sql);
 //设置参数
 ps.setString(1, name);
 ps.setString(2,password);
 ResultSet resultSet = ps.executeQuery();
 if (resultSet.next()) {
 System.out.println("登录成功:" + name);
 }
 else {
 System.out.println("登录失败");
 }
 //释放资源,子接口直接给父接口
 JdbcUtils.close(connection,ps,resultSet);
 } }

JDBC事务的处理

在这里插入图片描述
步骤:

  1. 获取连接
  2. 开启事务
  3. 获取到 PreparedStatement
  4. 使用 PreparedStatement 执行两次更新操作
  5. 正常情况下提交事务
  6. 出现异常回滚事务
  7. 最后关闭资源

案例代码

package com.itheima;
import com.itheima.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Demo12Transaction {
 //没有异常,提交事务,出现异常回滚事务
 public static void main(String[] args) {
21 / 21 
 //1) 注册驱动
 Connection connection = null;
 PreparedStatement ps = null;
 try {
 //2) 获取连接
 connection = JdbcUtils.getConnection();
 //3) 开启事务
 connection.setAutoCommit(false);
 //4) 获取到 PreparedStatement
 //从 jack 扣钱
 ps = connection.prepareStatement("update account set balance = balance - ? where
name=?");
 ps.setInt(1, 500);
 ps.setString(2,"Jack");
 ps.executeUpdate();
 //出现异常
 System.out.println(100 / 0);
 //给 rose 加钱
 ps = connection.prepareStatement("update account set balance = balance + ? where
name=?");
 ps.setInt(1, 500);
 ps.setString(2,"Rose");
 ps.executeUpdate();
 //提交事务
 connection.commit();
 System.out.println("转账成功");
 } catch (Exception e) {
 e.printStackTrace();
 try {
 //事务的回滚
 connection.rollback();
 } catch (SQLException e1) {
 e1.printStackTrace();
 }
 System.out.println("转账失败");
 }
 finally {
 //7) 关闭资源
 JdbcUtils.close(connection,ps);
 }
 } }

数据库连接池

  1. 概念:其实就是一个容器(集合),存放数据库连接的容器。
    当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。
    因为每次连接数据库都要创建一个连接对象,人们就想办法把这些连接对象集中起来,这样需要的时候就拿一个,不需要的时候就放回去。不用每次都重新创建,节约了资源,提高了效率。

    1. 好处:

      1. 节约资源
      2. 用户访问高效
    2. 实现:

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

        1. 方法:
          • 获取连接:getConnection()
          • 归还连接:Connection.close()。如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了。而是归还连接
      2. 一般我们不去实现它,有数据库厂商来实现

        1. C3P0:数据库连接池技术
        2. Druid:数据库连接池实现技术,由阿里巴巴提供的(更加先进)

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>
  <!-- 使用默认的配置读取连接池对象 -->
  <default-config>
  	<!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/day25</property>
    <property name="user">root</property>
    <property name="password">root</property>
    
    <!-- 连接池参数 -->
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">10</property>
    <property name="checkoutTimeout">3000</property>
  </default-config>

  <named-config name="otherc3p0"> 
    <!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/day25</property>
    <property name="user">root</property>
    <property name="password">root</property>
    
    <!-- 连接池参数 -->
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">8</property>
    <property name="checkoutTimeout">1000</property>
  </named-config>
</c3p0-config>
			* 路径:直接将文件放在src目录下即可。

这是c3p0的xml配置文件,连接池参数中initialPoolSize是连接池中的默认连接对象的数量,
maxPoolSize是最大的连接对象数量,获取超过这个数量就会报错。
checkoutTimeout是获取等待时长,如果超过这个时间就会认为没有获取到,系统报错。

  1. 创建核心对象 数据库连接池对象 ComboPooledDataSource
  2. 获取连接: getConnection
    * 代码:
    //1.创建数据库连接池对象
    DataSource ds = new ComboPooledDataSource();
    //2. 获取连接对象
    Connection conn = ds.getConnection();
    其他步骤相同唯一的不同就是先获取一个连接池,然后从连接池中去获取连接对象。

Druid

  1. 步骤:
    1. 导入jar包 druid-1.0.9.jar
    2. 定义配置文件:
    * 是properties形式的
    * 可以叫任意名称,可以放在任意目录下
    3. 加载配置文件。Properties
    4. 获取数据库连接池对象:通过工厂来来获取 DruidDataSourceFactory
    5. 获取连接:getConnection
    * 代码:
    //3.加载配置文件
    Properties pro = new Properties();
    InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream(“druid.properties”);
    pro.load(is);
    //4.获取连接池对象
    DataSource ds = DruidDataSourceFactory.createDataSource(pro);
    //5.获取连接
    Connection conn = ds.getConnection();

创建一个Druid工具类

public class DruidUtil {
    private static Connection connection = null;
    private static Properties pro = null;

    static {
        pro = new Properties();
        InputStream is = DruidUtil.class.getClassLoader().getResourceAsStream("Druid.properties");
        try {
            pro.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
    }

    //返回连接池
    public static DataSource getDataSource() throws Exception {
        DataSource dataSource = DruidDataSourceFactory.createDataSource(pro);
        return dataSource;
    }

    //返回连接对象
    public static Connection getConnection() throws Exception {
        connection = getDataSource().getConnection();
        return connection;
    }

    //关闭资源
    public static void close(Connection connection, Statement statement, ResultSet resultSet) {
        try {
            if (connection != null)
                connection.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        try {
            if (statement != null)
                statement.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        try {
            if (resultSet != null)
                resultSet.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}

试用一下Druid工具类

public class DruidTest {
     static Connection connection = null;
    static PreparedStatement preparedStatement = null;


    public static void main(String[] args) {
        updateDatebase();
    }

    private static void updateDatebase() {
        try {
            connection=DruidUtil.getConnection();
            String sql="update account set zhanghu=2000 where id=?";
            preparedStatement=connection.prepareStatement(sql);
            preparedStatement.setInt(1,1);
            preparedStatement.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            DruidUtil.close(connection,preparedStatement,null);
        }


    }
}

Spring JDBC

  • Spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发

    • 步骤:
      1. 导入jar包

      2. 创建JdbcTemplate对象。依赖于数据源DataSource

        • JdbcTemplate template = new JdbcTemplate(ds);
      3. 调用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:查询结果,将结果封装为对象
          • 一般用于聚合函数的查询
    1. 练习:
      * 需求:
      1. 修改1号数据的 salary 为 10000
      2. 添加一条记录
      3. 删除刚才添加的记录
      4. 查询id为1的记录,将其封装为Map集合
      5. 查询所有记录,将其封装为List
      6. 查询所有记录,将其封装为Emp对象的List集合
      7. 查询总记录数
    • 代码:

        	public class JdbcTemplateDemo2 {
        	
        	    //Junit单元测试,可以让方法独立执行
        	
        	
        	    //1. 获取JDBCTemplate对象
        	    private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
        	    /**
        	     * 1. 修改1号数据的 salary 为 10000
        	     */
        	    @Test
        	    public void test1(){
        	
        	        //2. 定义sql
        	        String sql = "update emp set salary = 10000 where id = 1001";
        	        //3. 执行sql
        	        int count = template.update(sql);
        	        System.out.println(count);
        	    }
        	
        	    /**
        	     * 2. 添加一条记录
        	     */
        	    @Test
        	    public void test2(){
        	        String sql = "insert into emp(id,ename,dept_id) values(?,?,?)";
        	        int count = template.update(sql, 1015, "郭靖", 10);
        	        System.out.println(count);
        	
        	    }
        	
        	    /**
        	     * 3.删除刚才添加的记录
        	     */
        	    @Test
        	    public void test3(){
        	        String sql = "delete from emp where id = ?";
        	        int count = template.update(sql, 1015);
        	        System.out.println(count);
        	    }
        	
        	    /**
        	     * 4.查询id为1001的记录,将其封装为Map集合
        	     *注意:这个方法查询的结果集长度只能是1
        	     */
        	    @Test
        	    public void test4(){
        	        String sql = "select * from emp where id = ? or id = ?";
        	        Map<String, Object> map = template.queryForMap(sql, 1001,1002);
        	        System.out.println(map);
        	        //{id=1001, ename=孙悟空, job_id=4, mgr=1004, joindate=2000-12-17, salary=10000.00, bonus=null, dept_id=20}
        	
        	    }
        	
        	    /**
        	     * 5. 查询所有记录,将其封装为List
        	     */
        	    @Test
        	    public void test5(){
        	        String sql = "select * from emp";
        	        List<Map<String, Object>> list = template.queryForList(sql);
        	
        	        for (Map<String, Object> stringObjectMap : list) {
        	            System.out.println(stringObjectMap);
        	        }
        	    }
        	
        	    /**
        	     * 6. 查询所有记录,将其封装为Emp对象的List集合
        	     */
        	
        	    @Test
        	    public void test6(){
        	        String sql = "select * from emp";
        	        List<Emp> list = template.query(sql, new RowMapper<Emp>() {
        	
        	            @Override
        	            public Emp mapRow(ResultSet rs, int i) throws SQLException {
        	                Emp emp = new Emp();
        	                int id = rs.getInt("id");
        	                String ename = rs.getString("ename");
        	                int job_id = rs.getInt("job_id");
        	                int mgr = rs.getInt("mgr");
        	                Date joindate = rs.getDate("joindate");
        	                double salary = rs.getDouble("salary");
        	                double bonus = rs.getDouble("bonus");
        	                int dept_id = rs.getInt("dept_id");
        	
        	                emp.setId(id);
        	                emp.setEname(ename);
        	                emp.setJob_id(job_id);
        	                emp.setMgr(mgr);
        	                emp.setJoindate(joindate);
        	                emp.setSalary(salary);
        	                emp.setBonus(bonus);
        	                emp.setDept_id(dept_id);
        	
        	                return emp;
        	            }
        	        });
        	
        	
        	        for (Emp emp : list) {
        	            System.out.println(emp);
        	        }
        	    }
        	
        	    /**
        	     * 6. 查询所有记录,将其封装为Emp对象的List集合
        	     */
        	
        	    @Test
        	    public void test6_2(){
        	        String sql = "select * from emp";
        	        List<Emp> list = template.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class));
        	        for (Emp emp : list) {
        	            System.out.println(emp);
        	        }
        	    }
        	
        	    /**
        	     * 7. 查询总记录数
        	     */
        	
        	    @Test
        	    public void test7(){
        	        String sql = "select count(id) from emp";
        	        Long total = template.queryForObject(sql, Long.class);
        	        System.out.println(total);
        	    }
        	
        	}
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值