Java进阶学习第十七天——JDBC入门学习

41 篇文章 1 订阅
4 篇文章 0 订阅
文档版本开发工具测试平台工程名字日期作者备注
V1.02016.05.11lutianfeinone

JDBC

JDBC介绍

  • JDBC是什么?
    • JDBC(Java Data Base Connectivity,java数据库连接)
    • SUN公司为了简化、统一对数据库的操作,定义了一套Java操作数据库的规范,称之为JDBC。
    • 简单说,就是可以直接通过java语言去操作数据库。
    • jdbc是一套标准,它是由一些接口与类组成的。


组成JDBC的类和接口
  • java.sql
    • 类:DriverManger
    • 接口 Connection Statement ResultSet PreparedStatement CallableStatement(它是用于调用存储过程)
  • javax.sql
    • 接口 DataSource(数据源)

  • 什么是驱动?
    • 两个设备要进行通信,满足一定通信数据格式,数据格式由设备提供商规定,设备提供商为设备提供驱动软件,通过软件可以与该设备进行通信。


JDBC入门

第一个JDBC程序
  • 编程从user表中读取数据,并打印在命令行窗口中。
    • 一、搭建实验环境 :
      • 1、在mysql中创建一个库,并创建user表和插入表的数据。
      • 2、新建一个Java工程,并导入数据驱动。
    • 二、编写程序,在程序中加载数据库驱动
      • DriverManager. registerDriver(Driver driver)
    • 三、建立连接(Connection)
      • Connection conn = DriverManager.getConnection(url,user,pass);
    • 四、创建用于向数据库发送SQL的Statement对象,并发送sql
      • Statement st = conn.createStatement();
      • ResultSet rs = st.executeQuery(sql);
    • 五、从代表结果集的ResultSet中取出数据,打印到命令行窗口
    • 六、断开与数据库的连接,并释放相关资源

create table user(
  id int primary key auto_increment,
  username varchar(20) unique not null,
  password varchar(20) not null,
  email varchar(40) not null
);

INSERT INTO USER VALUES(NULL,'tom','123','tom@163.com');
INSERT INTO USER VALUES(NULL,'fox','123','fox@163.com');
  • 1.加载驱动
    • 将驱动jar包复制到lib下.
  • 2.创建一个JdbcDemo1类
public static void main(String[] args) throws SQLException {

    // 1.注册驱动
    // DriverManager.registerDriver(new Driver()); //加载了两个驱动
    Class.forName("com.mysql.jdbc.Driver"); // 加载mysql驱动

    // 2.获取连接对象
    Connection con = DriverManager.getConnection(
            "jdbc:mysql://localhost:3306/day17", "root", "abc");

    // 3.通过连接对象获取操作sql语句Statement
    Statement st = con.createStatement();

    // 4.操作sql语句
    String sql = "select * from user";

    // 操作sql语句(select语句),会得到一个ResultSet结果集
    ResultSet rs = st.executeQuery(sql);

    // 5.遍历结果集
    // boolean flag = rs.next(); // 向下移动,返回值为true,代表有下一条记录.
    // int id = rs.getInt("id");
    // String username=rs.getString("username");
    // System.out.println(id);
    // System.out.println(username);

    while(rs.next()){
        int id=rs.getInt("id");
        String username=rs.getString("username");
        String password=rs.getString("password");
        String email=rs.getString("email");

        System.out.println(id+"  "+username+"  "+password+"  "+email);
    }

    //6.释放资源
    rs.close();
    st.close();
    con.close();
}


JDBC操作详解

1.注册驱动
  • JDBC程序中的DriverManagerjava.sql包下的一个驱动管理的工具类,可以理解成是一个容器(Vector),可以装入很多数据库驱动,并创建与数据库的链接,这个API的常用方法:

    • DriverManager.registerDriver(new Driver())
    • DriverManager.getConnection(url, user, password),
  • registDriver方法分析

    • public static synchronized void registerDriver(java.sql.Driver driver)
      • 参数:java.sql.Driver
      • 我们传递的是 : com.mysql.jdbc.Driver;
    • 在com.mysql.jdbc.Driver类中有一段静态代码块:
static {
    try {
        java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
        throw new RuntimeException("Can't register driver!");
    }
}
  • 上述代码的问题:

    • 1.在驱动管理器中会装入两个mysql驱动.
      • 解决方案:使用反射 Class.forName("com.mysql.jdbc.Driver");
      • 分析:使用反射的方式来加载驱动有什么好处?
        • 一、查看Driver的源代码可以看到,如果采用此种方式,会导致驱动程序注册两次,也就是在内存中会有两个Driver对象。
        • 二、程序依赖mysql的api,脱离mysql的jar包,程序将无法编译,将来程序切换底层数据库将会非常麻烦。
    • 2.可以通过DriverManager来获取连接对象
      • Connection con=DriverManager.getConection(String url,String user,String password);
      • url作用:就是用于确定使用哪一个驱动.
        • mysql url: jdbc: mysql ://localhsot:3306/数据库名
        • oralce url: jdbc : oracle :thin :@ localhost :1521 :sid
  • DriverManager作用总结:

    • 1.注册驱动
    • 2.获取连接Connection
数据库URL
  • URL用于标识数据库的位置,程序员通过URL地址告诉JDBC程序连接哪个数据库,URL的写法为:

    • jdbc : mysql : // localhost :3306/test ?key=value
  • url格式

    • 主协议 子协议 主机 端口 数据库
    • jdbc : mysql ://localhost:3306/day17
  • mysql的url可以简写

    • 前提:主机是:localhost 端口是 :3306
    • jdbc : mysql : ///day17
  • 在url后面可以带参数

    • eg: useUnicode=true&characterEncoding=UTF-8


2.Connection详解
  • java.sql.Connection,它代表的是一个连接对象。简单说,就是我们程序与数据库连接。

  • Connection作用:

    • 1.可以通过Connection获取操作SQLStatement对象
      • Statement createStatement() throws SQLException
      • 示例:
        • Statement st=con.createStatement();
    • 2.操作事务
      • setAutoCommit(boolean flag);开启事务,设置事务是否自动提交。
      • rollback();事务回滚,在此链接上回滚事务。
      • commit();事务提交,在链接上提交事务。 —与事务相关!!
    • 了解:
      • 1.可以获取执行预处理PreparedStatement对象.创建向数据库发送预编译sql的PrepareSatement对象
        • PreparedStatement prepareStatement(String sql) throws SQLException
      • 2.可以获取执行存储过程CallableStatement,创建执行存储过程的callableStatement对象。
        • CallableStatement prepareCall(String sql) throws SQLException


3.Statement详解
  • java.sql.Statement用于向数据库发送SQL语句,执行sql语句
Statement作用
  • 1.执行SQL

    • DML : insert update delete
      • int executeUpdate(String sql) :用于向数据库发送insert、update或delete语句
        • 利用返回值判断非0来确定sql语句是否执行成功。
    • DQL : select
      • ResultSet executeQuery(String sql) : 用于向数据发送查询语句。
    • execute(String sql):用于向数据库发送任意SQL语句
  • 2.批处理操作

    • addBatch(String sql); 将SQL语句添加到批处理
    • executeBatch(); 向数据库发送一批SQl语句执行。
    • clearBatch(); 清空批处理。


4.ResultSet详解
  • java.sql.ResultSet它是用于封装select语句执行后查询的结果。Resultset封装执行结果时,采用的类似于表格的方式。ResultSet 对象维护了一个指向表格数据行的游标cursor,初始的时候,游标在第一行之前,调用ResultSet.next() 方法,可以使游标指向具体的数据行,进而调用方法获取该行的数据。
ResultSet常用API
  • 1.next()方法

    • public boolean next();
    • 用于判断是否有下一条记录。如果有返回true,并且让游标向下移动一行
    • 如果没有返回false.
  • 2.可以通过ResultSet提供的getXxx()方法来获取当前游标指向的这条记录中的列数据。

    • 常用:
      • getInt()
      • getString(int index)
      • getString(String columnName):也可以获得int,Data等类型
      • getDate()
      • getDouble()
    • 参数有两种
      • 1.getInt(int columnIndex);
      • 2.getInt(String columnName);
  • 如果列的类型不知道,可以通过下面的方法来操作

    • getObject(int columnIndex);
    • getObject(String columnName);
  • 常用数据类型转换表


释放资源
  • JDBC程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象,这些对象通常是ResultSet, Statement和Connection对象。

  • 特别是Connection对象,它是非常稀有的资源,用完后必须马上释放,如果Connection不能及时、正确的关闭,极易导致系统宕机

  • Connection的使用原则是尽量晚创建尽量早的释放
  • 为确保资源释放代码能运行,资源释放代码也一定要放在finally语句中。

  • 完整版JDBC示例代码:

    public static void main(String[] args) {
        Connection con = null;
        Statement st = null;
        ResultSet rs = null;
        try {
            // 1.注册驱动

            Class.forName("com.mysql.jdbc.Driver");

            // 2.获取连接
            con = DriverManager.getConnection("jdbc:mysql:///day17", "root",
                    "abc");

            // 3.获取操作sql语句对象Statement
            st = con.createStatement();

            // 4.执行sql
            rs = st.executeQuery("select * from user");

            // 5.遍历结果集
            while (rs.next()) {
                int id = rs.getInt("id");
                String username = rs.getString("username");
                String password = rs.getString("password");
                String email = rs.getString("email");

                System.out.println(id + "  " + username + "  " + password
                        + "  " + email);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 6.释放资源

            try {
                if (rs != null) {
                    rs.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }

            try {
                if (st != null)
                    st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (con != null)
                    con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}


使用JDBC对数据库进行CRUD

  • Jdbc中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。

  • Statement对象的executeUpdate方法,用于向数据库发送增、删、改的sql语句,executeUpdate执行完后,将会返回一个整数(即增删改语句导致了数据库几行数据发生了变化)。

  • Statement.executeQuery方法用于向数据库发送查询语句,executeQuery方法返回代表查询结果的ResultSet对象。

  • 1.查询

    • 1.查询全部
    • 2.条件查询—根据id
  • 2.修改
  • 3.删除
  • 4.添加

  • 练习:编写程序对User表进行增删改查操作。

  • 练习:编写工具类简化CRUD操作。(异常暂不处理)


JdbcUtils工具类
  • 只抽取到Connection
//jdbc.properties
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql:///day17
username=root
password=abc




public class JdbcUtils {


    private static final String DRIVERCLASS;
    private static final String URL;
    private static final String USERNAME;
    private static final String PASSWORD;

    static {
        DRIVERCLASS = ResourceBundle.getBundle("jdbc").getString("driverClass");
        URL = ResourceBundle.getBundle("jdbc").getString("url");
        USERNAME = ResourceBundle.getBundle("jdbc").getString("username");
        PASSWORD = ResourceBundle.getBundle("jdbc").getString("password");
    }

    static {
        try {
            // 将加载驱动操作,放置在静态代码块中.这样就保证了只加载一次.
            Class.forName(DRIVERCLASS);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() throws SQLException {

        // 2.获取连接
        Connection con = DriverManager.getConnection(URL, USERNAME, PASSWORD);

        return con;
    }

    //关闭操作
    public static void closeConnection(Connection con) throws SQLException{
        if(con!=null){
            con.close();
        }
    }
    public static void closeStatement(Statement st) throws SQLException{
        if(st!=null){
            st.close();
        }
    }
    public static void closeResultSet(ResultSet rs) throws SQLException{
        if(rs!=null){
            rs.close();
        }
    }
}


  • JDBC CURD
//jdbc的crud操作
public class JdbcDemo6 {

    @Test
    public void findByIdTest() {
        // 1.定义sql
        String sql = "select * from user where id=1";

        Connection con = null;
        Statement st = null;
        ResultSet rs = null;
        try {
            // 1.注册驱动

            Class.forName("com.mysql.jdbc.Driver");

            // 2.获取连接
            con = DriverManager.getConnection("jdbc:mysql:///day17", "root",
                    "abc");

            // 3.获取操作sql语句对象Statement
            st = con.createStatement();

            // 4.执行sql
            rs = st.executeQuery(sql);

            // 5.遍历结果集
            while (rs.next()) {
                int id = rs.getInt("id");
                String username = rs.getString("username");
                String password = rs.getString("password");
                String email = rs.getString("email");

                System.out.println(id + "  " + username + "  " + password
                        + "  " + email);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 6.释放资源

            try {
                if (rs != null) {
                    rs.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }

            try {
                if (st != null)
                    st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (con != null)
                    con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    // 添加操作
    @Test
    public void addTest() {
        // 定义sql
        String sql = "insert into user values(null,'张三','123','zs@163.com')";
        Connection con = null;
        Statement st = null;
        ResultSet rs = null;
        try {
            // 1.注册驱动

            Class.forName("com.mysql.jdbc.Driver");

            // 2.获取连接
            con = DriverManager.getConnection("jdbc:mysql:///day17", "root",
                    "abc");

            // 3.获取操作sql语句对象Statement
            st = con.createStatement();

            // 4.执行sql
            int row = st.executeUpdate(sql);

            if (row != 0) {
                System.out.println("添加成功");
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 6.释放资源

            try {
                if (rs != null) {
                    rs.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }

            try {
                if (st != null)
                    st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (con != null)
                    con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    // update操作
    @Test
    public void updateTest() {
        // 将id=3的人的password修改为456
        String password = "456";
        String sql = "update user set password='" + password + "' where id=3";

        // 1.得到Connection
        Connection con = null;
        Statement st = null;
        try {
            con = JdbcUtils1.getConnection();

            // 3.获取操作sql语句对象Statement
            st = con.createStatement();

            // 4.执行sql
            int row = st.executeUpdate(sql);

            if (row != 0) {
                System.out.println("修改成功");
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            try {
                if (st != null)
                    st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (con != null)
                    con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }

    // delete测试
    @Test
    public void deleteTest() {
        // 将id=3的人删除

        String sql = "delete from user where id=2";

        // 1.得到Connection
        Connection con = null;
        Statement st = null;
        try {
            con = JdbcUtils.getConnection();

            // 3.获取操作sql语句对象Statement
            st = con.createStatement();

            // 4.执行sql
            int row = st.executeUpdate(sql);

            if (row != 0) {
                System.out.println("删除成功");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源

            try {
                JdbcUtils.closeStatement(st);
                JdbcUtils.closeConnection(con);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }
}


ResultSet 滚动结果集

  • 默认得到的ResultSet它只能向下遍历(next()),对于ResultSet它可以设置成是滚动的,可以向上遍历,或者直接定位到一个指定的物理行号。

  • 设置滚动结果集的方法

    • 在创建Statement对象时,不使用createStatement();而使用带参数的createStatement(int,int)
Statement createStatement(int resultSetType,
                          int resultSetConcurrency)
                          throws SQLException
、
Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
  • 第一个参数值, resultSetType

    • ResultSet.TYPE_FORWARD_ONLY 该常量指示光标只能向前移动的 ResultSet 对象的类型。
    • ResultSet.TYPE_SCROLL_INSENSITIVE 该常量指示可滚动但通常不受 ResultSet 底层数据更改影响的 ResultSet 对象的类型。
    • ResultSet.TYPE_SCROLL_SENSITIVE 该常量指示可滚动并且通常受 ResultSet 底层数据更改影响的 ResultSet 对象的类型。
  • 第二个参数值,resultSetConcurrency

    • ResultSet.CONCUR_READ_ONLY 该常量指示不可以更新的 ResultSet 对象的并发模式。
    • ResultSet.CONCUR_UPDATABLE 该常量指示可以更新的 ResultSet 对象的并发模式。
  • 以上五个值,可以有三种搭配方式

    • ResultSet.TYPE_FORWARD_ONLY ResultSet.CONCUR_READ_ONLY 默认,不受底层影响
    • ResultSet.TYPE_SCROLL_INSENSITIVE ResultSet.CONCUR_READ_ONLY
    • ResultSet.TYPE_SCROLL_SENSITIVE ResultSet.CONCUR_UPDATABLE 滚动的,可以并发更新的
  • 常用API

    • next():移动到下一行
    • previous():移动到前一行
    • absolute(int row):移动到指定行
    • beforeFirst():移动resultSet的最前面
    • afterLast() :移动到resultSet的最后面
    • updateRow() :更新行数据




DAO模式——JavaEE模式

  • DAO模式(Data Access Object 数据访问对象):在持久层通过DAO将数据源操作完全封装起来,业务层通过操作Java对象,完成对数据源操作
  • 业务层无需知道数据源底层实现 ,通过java对象操作数据源


DAO模式结构
  • 1、DataSource数据源(MySQL数据库)
  • 2、Business Object 业务层代码,调用DAO完成 对数据源操作 (代表数据的使用者)
  • 3、DataAccessObject 数据访问对象,持久层DAO程序,封装对数据源增删改查,提供方法参数都是Java对象
  • 4、TransferObject 传输对象(值对象) 业务层通过向数据层传递 TO对象,完成对数据源的增删改查(表示数据的Java Bean)


使用dao模式完成登录操作
  • 需求:

    • 1、把文件换成数据库
    • 2、使用DAO模式
    • 3、防范sql注入攻击
  • 1.web层

    • login.jsp LoginServlet User
  • 2.service层
    • UserService(实际应是接口)
  • 3.dao层
    • UserDao(实际应是接口)

  • 具体代码见工程day17_2

  • 用户注册流程

sql注入
  • 由于没有对用户输入进行充分检查,而SQL又是拼接而成,在用户输入参数时,在参数中添加一些SQL 关键字,达到改变SQL运行结果的目的,也可以完成恶意攻击。
  • 1、statement存在sql注入攻击问题
    • 例如登陆用户名采用 xxx’ or ‘1’=‘1
    • 使用mysql注释
  • 2、对于防范 SQL 注入,可以采用PreparedStatement取代Statement

    • 它是一个预处理的Statement,它是java.sql.Statement接口的一个子接口。
    • PreparedStatement是Statement的子接口,它的实例对象可以通过调Connection.preparedStatement(sql)方法获得
    • Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出。PreparedStatement 可对SQL进行预编译,从而提高数据库的执行效率。
    • PreperedStatement对于sql中的参数,允许使用占位符的形式进行替换,简化sql语句的编写。
  • PreparedStatement使用总结

    • 1.在sql语句中,使用?占位
      • String sql=”select * from user where username=? and password=?”;
    • 2.得到PreparedStatement对象
      • PreparedStatement pst=con.prepareStatement(String sql);
    • 3.对占位符赋值
      • pst.setXxx(int index,Xxx obj);
      • 例如:
        • setInt()
        • setString();
        • 参数index,代表的是”?“的序号.注意:从1开始。
    • 4.执行sql
      • DML: pst.executeUpdate();
      • DQL: pst.executeQuery();
      • 注意:这两方法无参数
  • 关于PreparedStatement优点:

    • 1.解决sql注入(具有预处理功能)
    • 2.不需要再拼sql语句。



jdbc处理大数据

  • 在实际开发中,程序需要把大文本 Text 或二进制数据 Blob保存到数据库。

    • Text是mysql叫法,Oracle中叫Clob
  • 大数据也称之为LOB(Large Objects),LOB又分为:

    • clob用于存储大文本。Text
    • blob用于存储二进制数据,例如图像、声音、二进制文等。
  • Text和blob分别又分为:

    • Text(clob)
      • TINYTEXT(255B)、TEXT(64kb)、MEDIUMTEXT(16M)和LONGTEXT(4G)
    • blob
      • TINYBLOB(255B)、BLOB(64kb)、MEDIUMBLOB(16M)和LONGBLOB(4G)
  • 对于大数据操作,我们一般只有两种: insert select

  • 演示1: 大二进制操作

create table myblob(
id int primary key auto_increment,
content longblob
)
public class MyBlobTest {

    // 添加
    @Test
    public void save() throws SQLException, IOException {
        String sql = "insert into myblob values(null,?)";

        // 1.获取Connection
        Connection con = JdbcUtils.getConnection();
        // 2.获取PreparedStatement
        PreparedStatement pst = con.prepareStatement(sql);
        // 3.插入值
        File file = new File("D:\\java1110\\day17-jdbc\\视频\\3.jdbc快速入门.avi");
        FileInputStream fis = new FileInputStream(file);
        pst.setBinaryStream(1, fis, (int) (file.length())); //MySQL驱动只支持最后一个参数为int类型的方法
        int row = pst.executeUpdate();

        if (row != 0) {
            System.out.println("插入成功");
        }

        // 4.释放资源
        fis.close();
        pst.close();
        con.close();

    }

    // 获取
    @Test
    public void get() throws SQLException, IOException {
        String sql = "select * from myblob where id=?";

        // 1.获取Connection
        Connection con = JdbcUtils.getConnection();
        // 2.获取PreparedStatement
        PreparedStatement pst = con.prepareStatement(sql);
        pst.setInt(1, 1);
        // 3.得到结果集
        ResultSet rs = pst.executeQuery();

        // 4.遍历结果集
        if (rs.next()) {
            // System.out.println(rs.getInt("id"));

            InputStream is = rs.getBinaryStream("content");// 得到的这个输入流它的源可以理解成就是数据库中的大二进制信息

            FileOutputStream fos = new FileOutputStream("d:/a.avi");

            int len = -1;
            byte[] b = new byte[1024 * 100];

            while ((len = is.read(b)) != -1) {
                fos.write(b, 0, len);
                fos.flush();
            }
            fos.close();
            is.close();

        }

        // 5.关闭
        rs.close();
        pst.close();
        con.close();
    }
}
  • 向表中插入数据可能出现的问题

  • 问题1:java.lang.AbstractMethodError: com.mysql.jdbc.PreparedStatement.setBinaryStream(ILjava/io/InputStream;)

  • 原因:mysql驱动不支持setBinaryStream(int,InputStream);

  • 修改成 pst.setBinaryStream(1, fis,file.length());

  • 原因:因为mysql驱动不支 setBinaryStream(int,InputStream,long);

  • 解决: mysql驱动支持setBinaryStream(int,InputStream,int);

  • 注意:如果文件比较大,那么需要在my.ini文件中配置

    • max_allowed_packet=64M
  • 总结:

    • :pst.setBinaryStream(1, fis, (int) (file.length()));
    • :InputStream is = rs.getBinaryStream(“content”);


使用JDBC处理大文本
  • 对于MySQL中的Text类型,可调用如下方法设置
PreparedStatement.setCharacterStream(index, reader, length);
//注意length长度须设置,并且设置为int型
//当包过大时修改配置:[mysqld] max_allowed_packet=64M
  • 对MySQL中的Text类型,可调用如下方法获取
reader = resultSet. getCharacterStream(i);
等价于
reader = resultSet.getClob(i).getCharacterStream();
  • 演示:存储大文本
create table mytext(
id int primary key auto_increment,
content longtext
)

//存储
File file = new File("D:\\java1110\\workspace\\day17_3\\a.txt");
FileReader fr = new FileReader(file);
pst.setCharacterStream(1, fr, (int) (file.length()));

//获取:
Reader r = rs.getCharacterStream("content");


使用JDBC处理二进制数据
  • 对于MySQL中的BLOB类型,可调用如下方法设置
    • PreparedStatement. setBinaryStream(i, inputStream, length);
  • 对MySQL中的BLOB类型,可调用如下方法获取
    • InputStream in = resultSet.getBinaryStream(i);
    • InputStream in = resultSet.getBlob(i).getBinaryStream();
public class MyTextTest {

    // 存储
    @Test
    public void save() throws SQLException, FileNotFoundException {
        String sql = "insert into mytext values(null,?)";

        // 1.获取Connection
        Connection con = JdbcUtils.getConnection();
        // 2.获取PreparedStatement
        PreparedStatement pst = con.prepareStatement(sql);
        // 3.插入值
        File file = new File("D:\\java1110\\workspace\\day17_3\\a.txt");
        FileReader fr = new FileReader(file);
        pst.setCharacterStream(1, fr, (int) (file.length()));

        pst.executeUpdate();

        // 4.释放资源
        pst.close();
        con.close();
    }

    // 获取
    @Test
    public void get() throws SQLException, IOException {
        String sql = "select * from mytext where id=?";

        // 1.获取Connection
        Connection con = JdbcUtils.getConnection();
        // 2.获取PreparedStatement
        PreparedStatement pst = con.prepareStatement(sql);
        pst.setInt(1, 1);
        // 3.得到结果集
        ResultSet rs = pst.executeQuery();

        // 4.遍历结果集
        if (rs.next()) {
            Reader r = rs.getCharacterStream("content");

            FileWriter fw = new FileWriter("d:/笔记.txt");

            int len = -1;
            char[] ch = new char[1024 * 100];

            while ((len = r.read(ch)) != -1) {
                fw.write(ch, 0, len);
                fw.flush();
            }
            fw.close();
            r.close();

        }

        pst.close();
        con.close();
    }
}



JDBC批处理

  • 业务场景:当需要向数据库发送一批SQL语句执行时,应避免向数据库一条条的发送执行,而应采用JDBC的批处理机制,以提升执行效率。

  • 实现批处理有两种方式,第一种方式:

    • Statement.addBatch(sql)
    • executeBatch()方法:执行批处理命令
    • clearBatch()方法:清除批处理命令
  • 采用Statement.addBatch(sql)方式实现批处理:

    • 优点:可以向数据库发送多条不同的SQL语句。
    • 缺点:
      • SQL语句没有预编译。
      • 当向数据库发送多条语句相同,但仅参数不同的SQL语句时,需重复写上很多条SQL语句。例如:
        • Insert into user(name,password) values(‘aa’,’111’);
        • Insert into user(name,password) values(‘bb’,’222’);
        • Insert into user(name,password) values(‘cc’,’333’);
        • Insert into user(name,password) values(‘dd’,’444’);
  • 实现批处理的第二种方式

    • PreparedStatement.addBatch()
      • addBatch();
      • executeBatch();
      • clearBatch();
  • 采用PreparedStatement.addBatch()实现批处理

    • 优点:发送的是预编译后的SQL语句,执行效率高。
    • 缺点:只能应用在SQL语句相同,但参数不同的批处理中。因此此种形式的批处理经常用于在同一个表中批量插入数据,或批量更新表的数据。
  • 两个对象执行批处理区别?

    • 1.Statement它更适合执行不同sql的批处理。它没有提供预处理功能,性能比较低。
    • 2.PreparedStatement它适合执行相同sql的批处理,它提供了预处理功能,性能比较高。


  • eg:第一种方式
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtil.getConnection();
String sql1 = "insert into person(name,password,email,birthday) 
    values('kkk','123','abc@sina.com','1978-08-08')";
String sql2 = "update user set password='123456' where id=3";
st = conn.createStatement();
st.addBatch(sql1);  //把SQL语句加入到批命令中
st.addBatch(sql2);  //把SQL语句加入到批命令中
st.executeBatch();
} finally{
    JdbcUtil.free(conn, st, rs);
}
  • eg:第二种方式
conn = JdbcUtil.getConnection();
String sql = "insert into person(name,password,email,birthday) values(?,?,?,?)";
st = conn.prepareStatement(sql);
for(int i=0;i<50000;i++){
st.setString(1, "aaa" + i);
st.setString(2, "123" + i);
st.setString(3, "aaa" + i + "@sina.com");
st.setDate(4,new Date(1980, 10, 10));

st.addBatch(); 
if(i%1000==0){
st.executeBatch();
st.clearBatch();
}
}
st.executeBatch();


  • 注意;mysql默认情况下,批处理中的预处理功能没有开启,需要开启
    • 1.在 url下添加参数
      • url=jdbc :mysql :///day17?useServerPrepStmts=true&cachePrepStmts=true&rewriteBatchedStatements=true
    • 2.注意驱动版本
      • Mysql驱动要使用mysql-connector-java-5.1.13以上

  • 作业:
  • 1.注册+登录案例
  • 采用dao模式 使用PreparedStatement操作

  • 2.使用PreparedStatement完成CRUD

  • 客户信息表DAO编写

    • 创立如下数据库表customer,并编写DAO进行crud操作

  • 6
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JDBCJava Database Connectivity)是Java语言操作数据库的基础API,它提供了一种标准的方法来连接和操作各种关系型数据库。 JDBC的基本使用分为以下几个步骤: 1. 加载驱动程序:在使用JDBC操作数据库之前,需要先加载相应的驱动程序。不同的数据库需要加载不同的驱动程序,一般情况下驱动程序的jar包都会提供。 ```java Class.forName("com.mysql.jdbc.Driver"); ``` 2. 建立连接:使用DriverManager类的getConnection()方法连接数据库。 ```java String url = "jdbc:mysql://localhost:3306/test?useSSL=false"; String username = "root"; String password = "123456"; Connection conn = DriverManager.getConnection(url, username, password); ``` 其中url为连接数据库的URL,username和password为连接数据库的用户名和密码。 3. 创建Statement对象:通过Connection对象的createStatement()方法创建一个Statement对象,用于执行SQL语句。 ```java Statement stmt = conn.createStatement(); ``` 4. 执行SQL语句:可以通过Statement对象的execute()或executeQuery()方法执行SQL语句,如果是更新操作则使用executeUpdate()方法。 ```java ResultSet rs = stmt.executeQuery("SELECT * FROM users"); ``` 5. 处理结果集:如果执行的SQL语句返回了结果集,则可以通过ResultSet对象进行处理。 ```java while (rs.next()) { int id = rs.getInt("id"); String name = rs.getString("name"); System.out.println("id: " + id + ", name: " + name); } ``` 6. 关闭连接:使用完数据库后需要关闭连接,释放资源。 ```java rs.close(); stmt.close(); conn.close(); ``` 以上就是JDBC的基本使用过程,通过JDBC可以实现Java程序与数据库的交互,完成各种数据库操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值