JDBC 笔记

概述

1. 数据的持久化

  • 持久化(persistence):把数据保存到可掉电式存储设备中以供之后使用。大多数情况下,特别是企业级应用,数据持久化意味着将内存中的数据保存到硬盘上加以”固化”,而持久化的实现过程大多通过各种关系数据库来完成

  • 持久化的主要应用是将内存中的数据存储在关系型数据库中,当然也可以存储在磁盘文件、XML数据文件中。

 2. Java中的数据存储技术

  • 在Java中,数据库存取技术可分为如下几类:

    • JDBC直接访问数据库

    • JDO (Java Data Object )技术

    • 第三方O/R工具,如Hibernate, Mybatis 等

  • JDBC是java访问数据库的基石,JDO、Hibernate、MyBatis等只是更好的封装了JDBC。

3. JDBC介绍

  • JDBC(Java Database Connectivity)是一个独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(一组API),定义了用来访问数据库的标准Java类库,(java.sql,javax.sql)使用这些类库可以以一种标准的方法、方便地访问数据库资源。
  • JDBC为访问不同的数据库提供了一种统一的途径,为开发者屏蔽了一些细节问题。
  • JDBC的目标是使Java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,这样就使得程序员无需对特定的数据库系统的特点有过多的了解,从而大大简化和加快了开发过程。
  • 如果没有JDBC,那么Java程序访问数据库时是这样的:

 有了JDBC,Java程序访问数据库时是这样的:

  •  总结如下:

 4. JDBC体系结构

  • JDBC接口(API)包括两个层次:
    • 面向应用的API:Java API,抽象接口,供应用程序开发人员使用(连接数据库,执行SQL语句,获得结果)。
    • 面向数据库的API:Java Driver API,供开发商开发数据库驱动程序用。

JDBC是sun公司提供一套用于数据库操作的接口,java程序员只需要面向这套接口编程即可。

不同的数据库厂商,需要针对这套接口,提供不同实现。不同的实现的集合,即为不同数据库的驱动。 ————面向接口编程

5. JDBC程序编写步骤

补充:ODBC(Open Database Connectivity,开放式数据库连接),是微软在Windows平台下推出的。使用者在程序中只需要调用ODBC API,由 ODBC 驱动程序将调用转换成为对特定的数据库的调用请求。

第一个JDBC程序

1. 建立数据库

CREATE DATABASE jdbc CHARACTER SET utf8 COLLATE utf8_general_ci;

USE jdbc;

CREATE TABLE `users`(
id INT PRIMARY KEY,
NAME VARCHAR(40),
PASSWORD VARCHAR(40),
email VARCHAR(60),
birthday DATE
);

INSERT INTO `users`(id,NAME,PASSWORD,email,birthday)
VALUES(1,'zhansan','123456','zs@sina.com','1980-12-04'),
(2,'lisi','123456','lisi@sina.com','1981-12-04'),
(3,'wangwu','123456','wangwu@sina.com','1979-12-04')

2. 创建项目,这里使用Maven构建

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.peng</groupId>
    <artifactId>jdbc</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>

        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <!--dbcp连接池-->
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>commons-pool</groupId>
            <artifactId>commons-pool</artifactId>
            <version>1.6</version>
        </dependency>

        <!--单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>


</project>

3. 测试代码

@SuppressWarnings("all")
public class jdbc {

    @Test
    public void jdbcdemo () throws ClassNotFoundException,SQLException{

        //1.加载驱动
        Class.forName("com.mysql.jdbc.Driver");

        //2.用户信息和url
        String url="jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&&useSSL=false";
        String name="root";
        String password="peng";

        //3.连接成功,返回数据库对象,connection代表数据库
        Connection connection = DriverManager.getConnection(url, name, password);

        //4.执行SQL的对象statement
        Statement statement = connection.createStatement();

        //5.执行SQL的对象,去执行SQL 可能存在结果,查看返回结果
        String sql = "select * from users";
        ResultSet resultSet = statement.executeQuery(sql);
        while (resultSet.next()){
            System.out.println("name=" + resultSet.getObject("NAME"));
        }

        //6.释放连接
        resultSet.close();
        statement.close();
        connection.close();
    }
}

步骤总结:
加载驱动——连接数据库(DriverManager)——获取执行SQL的对象(Statement)——获得返回结果集——释放连接

Statement对象和PreparedStatement对象区别

Statement:

1. 创建db.properties存储配置信息

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&&useSSL=false
username=root
password=peng

2. 写工具类读取信

package com.peng.utils;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JdbcUtlis {

        private static String driver=null;
        private static String url=null;
        private static String username=null;
        private static String password=null;

        static{
            try {
                InputStream in = JdbcUtlis.class.getClassLoader().getResourceAsStream("db.properties");
                Properties properties = new Properties();
                properties.load(in);
                driver=properties.getProperty("driver");
                url=properties.getProperty("url");
                username=properties.getProperty("username");
                password=properties.getProperty("password");
                System.out.println(driver);
                //驱动只需要加载一次
                //Class.forName(driver);
                Class.forName("com.mysql.jdbc.Driver");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //获取连接
        public static Connection getConnection() throws SQLException {
            return DriverManager.getConnection(url, username, password);
        }
        //释放连接资源
        public static void release(Connection conn, Statement st, ResultSet rs){
            if(rs!=null){
                try {
                    rs.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if(st!=null){
                try {
                    st.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if(conn!=null){
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
}

3. 测试删除


    @Test
    public void TestDelete(){

        Connection conn = null;
        Statement st =null;
        ResultSet rs=null;

        try {
            conn = JdbcUtlis.getConnection();
            st = conn.createStatement();
            String sql = "delete from users where id=3";
            int delete = st.executeUpdate(sql);

            if (delete>0){
                System.out.println("delete success");
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtlis.release(conn,st,rs);
        }
    }

4. 测试插入


    @Test
    public void TestInsert(){

        Connection conn = null;
        Statement st =null;
        ResultSet rs=null;

        try {
            conn = JdbcUtlis.getConnection();
            st = conn.createStatement();
            String sql="insert into users(id,name,password,email,birthday)"+
                    "value(100,'刘备','123','123','1995-02-03')";
            int insert = st.executeUpdate(sql);
            if(insert>0)
                System.out.println("insert success");
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JdbcUtlis.release(conn,st,rs);
        }

    }

5. 测试更新


    @Test
    public void TestUpdate(){

        Connection conn = null;
        Statement st =null;
        ResultSet rs=null;

        try {
            conn = JdbcUtlis.getConnection();
            st = conn.createStatement();
            String sql="UPDATE users SET id=3,`NAME`='彪彪',`PASSWORD`='123456',email='123456789@qq.com',birthday='1997-05-02' WHERE id = 100";
            int update=st.executeUpdate(sql);
            if(update>0)
                System.out.println("update success");
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JdbcUtlis.release(conn,st,rs);
        }

    }

6. 测试查询


    @Test
    public void TestSelect(){

        Connection conn=null;
        Statement st=null;
        ResultSet rs=null;

        try {
            conn= JdbcUtlis.getConnection();
            st = conn.createStatement();
            String sql="SELECT * FROM users";
            //返回结果集
            rs=st.executeQuery(sql);
            while(rs.next()){
                System.out.print(rs.getInt("id") + "  ");
                System.out.print(rs.getString("NAME") + "  ");
                System.out.print(rs.getString("PASSWORD") + "  ");
                System.out.print(rs.getString("email") + "  ");
                System.out.println(rs.getDate("birthday"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtlis.release(conn,st,rs);
        }
    }

PreparedStatement:

只测试查询,增删改方法都和上面的差不多,只是改了try()里面的一点代码


    @Test
    public void TestprepareStatementSelect(){

        Connection conn=null;
        PreparedStatement st=null;
        ResultSet rs=null;

        try {
            conn= JdbcUtlis.getConnection();
            String sql="select * from users where id=?";
            st = conn.prepareStatement(sql);
            st.setInt(1,1);
            rs = st.executeQuery();
            while(rs.next()){
                System.out.print(rs.getInt("id") + "  ");
                System.out.print(rs.getString("NAME") + "  ");
                System.out.print(rs.getString("PASSWORD") + "  ");
                System.out.print(rs.getString("email") + "  ");
                System.out.println(rs.getDate("birthday"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtlis.release(conn,st,rs);
        }

    }

Statement 和 PreparedStatement之间的关系和区别:
    关系:PreparedStatement继承自Statement,都是接口
    区别:PreparedStatement可以使用占位符,是预编译的,批处理比Statement效率高

 
详解:
1. PreparedStatement:表示预编译的 SQL 语句的对象
2. 接口:public interface PreparedStatement extends Statement之间的继承关系
3. SQL 语句被预编译并存储在 PreparedStatement 对象中。然后可以使用此对象多次高效地执行该语句
4. Statement不能防止SQL注入,而PreparedStatement可以防止SQL注入。PreparedStatement本质是把传递进来的参数当做字符。      假设其中存在转义字符,如’ - 会被直接转义。

注:用于设置 IN 参数值的设置方法(setShort、setString 等等)必须指定与输入参数的已定义 SQL 类型兼容的类型。例如,如果 IN 参数具有 SQL 类型 INTEGER,那么应该使用 setInt 方法,问号的位置也是应该注意的,因为第一个问好的位置为1,第二个问号的位置为2.以此类推。

SQL注入攻击的原理连接:Sql注入基本原理_猿小雷的博客-CSDN博客_sql注入攻击的原理

JDBC事务

CREATE DATABASE IF NOT EXISTS `jdbc`;

CREATE TABLE `account`(
`id` INT(10) NOT NULL AUTO_INCREMENT COMMENT '用户户id',
`name` VARCHAR(20) NOT NULL COMMENT '用户名字',
`money` FLOAT NOT NULL COMMENT '用户金钱',
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO `account` (`name`,`money`) VALUES ('刘备',1000),('曹操',1000);

    @Test
    public void TestTransaction(){

        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtlis.getConnection();
            //关闭自动提交功能,开始事务
            conn.setAutoCommit(false);
            String sql1 = "UPDATE account set monet=money-100 WHERE name='刘备'";
            st = conn.prepareStatement(sql1);
            st.executeUpdate();

            //会导致操作失败,事务回滚。
            int x=1/0;

            String sql2 = "UPDATE account set monet=money+100 WHERE name='曹操'";
            st = conn.prepareStatement(sql2);
            st.executeUpdate();

            //业务完毕提交事务
            conn.commit();
            System.out.println("Success");

        } catch (SQLException throwables) {
            //如果失败则回滚
            try {
                conn.rollback();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            throwables.printStackTrace();
        } finally {
            JdbcUtlis.release(conn,st,rs);
        }
    }

DBCP数据库连接池

数据库连接——执行完毕——释放十分消耗资源
池化技术:准备一些预先的资源,过来就连接,使用预先准备好的服务。

  • 常用连接数10个
  • 最小连接数10个
  • 最大连接数15个(超过15个请求需要排队)
  • 等待超时:等待时间超过一定值直接失败

编写连接池:实现DataSource接口,开源数据源实现:DBCP、C3P0、Druid。使用连接池,省去直接使用getconnection()即可(不用手动编写)。

1. 配置文件

报错试设置useSSL=false;

#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=false
username=root
password=peng

#!-- 初始化连接 --
initialSize=10

#最大连接数量
maxActive=50

#!-- 最大空闲连接 --
maxIdle=20

#!-- 最小空闲连接 --
minIdle=5

#!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 --
maxWait=60000
#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:【属性名=property;】
#注意:user 与 password 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=UTF8

#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true

#driver default 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=

#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED

2. 工具类

package com.peng.utils;

import org.apache.commons.dbcp.BasicDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JdbcUtils_DBCP {
    private static DataSource dataSource=null;
    static {
        try {
            InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcp_config.properties");
            Properties properties=new Properties();
            properties.load(in);
            //创建数据源 工厂模式->创建
            dataSource= BasicDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //获取连接
    public static Connection getConnection() throws SQLException{
        return dataSource.getConnection();//从数据源获取连接
    }

    //释放连接资源
    public static void release(Connection conn, Statement st, ResultSet rs){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(st!=null){
            try {
                st.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

3. 测试查询,增删改都差不多


    @Test
    public void TestDBCP(){

            Connection conn = null;
            Statement st = null;
            ResultSet rs = null;

            try {

                conn = JdbcUtils_DBCP.getConnection();
                st = conn.createStatement();
                String sql = "SELECT * FROM users";

                //返回结果集
                rs = st.executeQuery(sql);
                while (rs.next()) {
                    System.out.print(rs.getInt("id") + "  ");
                    System.out.print(rs.getString("NAME") + "  ");
                    System.out.print(rs.getString("PASSWORD") + "  ");
                    System.out.print(rs.getString("email") + "  ");
                    System.out.println(rs.getDate("birthday"));
                }

            } catch (SQLException throwables) {
                throwables.printStackTrace();
            } finally {
                JdbcUtils_DBCP.release(conn, st, rs);
            }

    }

4. 项目结构图

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值