什么是JDBC?JDBC就是Java程序访问数据库的规范,是一个规范定义接口,各种数据库厂家实现了JDBC这个接口,这些实现类就是数据库驱动,使用时只需要调用接口中的方法即可,不用关注类是如何实现的。

JDBC的核心API有以下几种:

DriverManager类:管理和注册数据库驱动,获取数据库连接对象Connection接口:一个数据库连接对象,用于创建Statement和PreparedStatement对象Statement接口:一个数据库操作对象,用于执行sql语句PreparedStatement:一个数据库操作对象,用于执行sql语句,Statement的子接口ResultSet:用于封装数据库查询的结果集,返回给客户端Java程序

这些API怎么用后面会逐个介绍到。

JDBC经典6步:

public class Demo01 {    public static void main(String[] args) throws ClassNotFoundException, SQLException {        //1.加载注册驱动,省略了注册        Class.forName("com.mysql.jdbc.Driver");        //2.获取数据库连接对象        String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false";        String username="root";        String password="root";        Connection connection = DriverManager.getConnection(url, username, password);        //3.获取数据库操作对象        Statement statement = connection.createStatement();        //4.执行sql语句,返回结果或者行数        String sql="SELECT * FROM users";        ResultSet resultSet = statement.executeQuery(sql);        //5.处理结果        while(resultSet.next()){            System.out.println("id="+resultSet.getObject("id"));            System.out.println("NAME="+resultSet.getObject("NAME"));            System.out.println("PASSWORD="+resultSet.getObject("PASSWORD"));            System.out.println("email="+resultSet.getObject("email"));            System.out.println("birthday="+resultSet.getObject("birthday"));        }        //6.释放连接        resultSet.close();        statement.close();        connection.close();    }}
id=1NAME=zhansanPASSWORD=123456email=zs@sina.combirthday=1980-12-04id=2NAME=lisiPASSWORD=123456email=lisi@sina.combirthday=1981-12-04id=3NAME=wangwuPASSWORD=111111email=wangwu@qq.combirthday=1996-05-22

第一步:注册、加载驱动

实际上应该是这样的:

Driver driver=new com.mysql.jdbc.Driver();DriverManager.registerDriver(driver);

为什么这样只加载不注册也可以呢(mysql5之后)?

//1.加载注册驱动,省略了注册Class.forName("com.mysql.jdbc.Driver");

点开Driver类的源码发现:

类Driver实现了java.sql.Driver接口,在静态代码块中,DriverManager类的registerDriver方法注册了驱动,这样我们使用注解Class.forName加全类名就会自动执行静态代码块的内容,即自动注册了驱动,只需要加载即可。

第二步:获取数据库连接对象connection

DriverManager类:管理和注册数据库驱动,获取数据库连接对象DriverManager类的getConnection方法返回一个数据库连接对象
//2.获取数据库连接对象String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false";String username="root";String password="root";        Connection connection = DriverManager.getConnection(url, username, password);

第三步:获取数据库操作对象statement

Connection接口:一个数据库连接对象,用于创建Statement和PreparedStatement对象数据库连接对象connection的createStatement方法可以创建数据库操作对象Statementconnection还可以管理事务:connection.setAutoCommit(false);//开启事connection.commit();//提交事务connection.rollback();//回滚事务
Statement statement = connection.createStatement();

第四步:执行sql语句,返回结果或者行数

boolean execute(String sql):可以执行任意sqlint executeUpdate(String sql):执行DML语句(insert、delete、update),返回影响的行数ResultSet executeQuery(String sql):执行DQL(select)语句,返回结果集
//4.执行sql语句,返回结果或者行数String sql="SELECT * FROM users";ResultSet resultSet = statement.executeQuery(sql);

第五步:处理结果

如果执行的是DML语句则返回行数大于0表示执行成功,如果执行的是DQL语句,则返回结果集。

ResultSet:用于封装数据库查询的结果集,返回给客户端Java程序boolean next():游标向下移动一行,判断当前行是否有数据getXxx():获取数据,Xxx表示不同数据类型
while(resultSet.next()){      System.out.println("id="+resultSet.getObject("id"));      System.out.println("NAME="+resultSet.getObject("NAME"));      System.out.println("PASSWORD="+resultSet.getObject("PASSWORD"));      System.out.println("email="+resultSet.getObject("email"));      System.out.println("birthday="+resultSet.getObject("birthday"));}

第六步:释放连接

从小到大释放连接。

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

以上六步只是最基本的,为了避免空指针异常,改进如下:

public class Demo02 {    public static void main(String[] args) {        Connection conn=null;        Statement st=null;        ResultSet rs=null;        try {            //1.加载驱动            Class.forName("com.mysql.jdbc.Driver");            //2.获取数据库连接对象            conn= DriverManager.getConnection();            //3.获取数据库操作对象            st= conn.createStatement();            //4.执行sql语句,返回结果或者行数            String sql="SELECT * FROM users";            ResultSet resultSet = st.executeQuery(sql);            //5.处理结果            while(resultSet.next()){                System.out.println("id="+resultSet.getObject("id"));                System.out.println("NAME="+resultSet.getObject("NAME"));                System.out.println("PASSWORD="+resultSet.getObject("PASSWORD"));                System.out.println("email="+resultSet.getObject("email"));                System.out.println("birthday="+resultSet.getObject("birthday"));            }        } catch (SQLException throwables) {            throwables.printStackTrace();        }finally {            if(rs!=null) {        try {            rs.close();        } catch (Exception e) {            e.printStackTrace();        }        }       if(st!=null) {           try {               st.close();           } catch (Exception e) {               e.printStackTrace();           }       }       if(conn!=null) {           try {               conn.close();           } catch (Exception e) {               e.printStackTrace();           }       }        }    }}

上面的代码重复的太多,因此进行封装。

首先是数据库的注册与连接写入db.properties文件。

driver=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=falseusername=rootpassword=root

接着是获取连接对象和释放资源的代码抽取在jdbcutils中。

public class jdbcutils {    private static String driver=null;    private static String url=null;    private static String username=null;    private static String password=null;    static{        try {            InputStream in = jdbcutils.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");            Class.forName(driver);        }catch (Exception 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 (Exception e) {            e.printStackTrace();        }        }       if(st!=null) {           try {               st.close();           } catch (Exception e) {               e.printStackTrace();           }       }       if(conn!=null) {           try {               conn.close();           } catch (Exception e) {               e.printStackTrace();           }       }    }}

将注册驱动、获取连接对象和释放连接的代码抽取后,以上代码就可以写成如下,以后只需修改db.properties配置文件即可。

public class Demo02 {    public static void main(String[] args) {        Connection conn=null;        Statement st=null;        ResultSet rs=null;        try {            conn= jdbcutils.getConnection();            st= conn.createStatement();            String sql="SELECT * FROM users";            ResultSet resultSet = st.executeQuery(sql);            while(resultSet.next()){                System.out.println("id="+resultSet.getObject("id"));                System.out.println("NAME="+resultSet.getObject("NAME"));                System.out.println("PASSWORD="+resultSet.getObject("PASSWORD"));                System.out.println("email="+resultSet.getObject("email"));                System.out.println("birthday="+resultSet.getObject("birthday"));            }        } catch (SQLException throwables) {            throwables.printStackTrace();        }finally {            jdbcutils.release(conn,st,rs);        }    }}

工具齐全之后,开始看JDBC中存在的问题了:sql注入问题。

看一个sql语句:

select * from user where name="zhulin" and password='a' or '1'=1name="zhulin" and password='a'为假,'1'=1为真,or拼接之后,相当于select * from user where true;

这就是sql注入问题:用户输入的内容作为了SQL语句中的一部分,改变了原SQL的真正意义。

如何解决呢?还记得:

Connection接口:一个数据库连接对象,用于创建Statement和PreparedStatement对象

PreparedStatement对象正是用于解决这一问题。

public class Demo03 {    public static void main(String[] args) {        Connection conn=null;        PreparedStatement pstm=null;        try {            conn=jdbcutils.getConnection();            String sql="delete from users where id=?";            pstm=conn.prepareStatement(sql);//预编译             pstm.setInt(1,3);             int i=pstm.executeUpdate();             if(i>0){                 System.out.println("删除成功");             }        } catch (SQLException throwables) {            throwables.printStackTrace();        }finally {            jdbcutils.release(conn,pstm,null);        }    }}

mysql数据库产商在实现PreparedStatement接口的实现类中的setString(int parameterIndex, String x)函数中做了一些处理,把单引号做了转义(只要用户输入的字符串中有单引号,那mysql数据库产商的setString()这个函数,就会把单引号做转义)。

PreparedStatement会将SQL先发给数据库预编译,引用预编译后的结果,可以多次传入不同的参数给PreparedStatement对象并执行,减少SQL编译次数,提高效率,虽然多了几行代码,但安全性更高,解决了sql注入的隐患,提高了程序的可读性。

在前面提到Connection还可以管理事务,接着就简单介绍一下JDBC控制事务。

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

以一个转账的例子介绍:Navicat中建account表

public class DemoTrasaction {    public static void main(String[] args) {        Connection conn = null;        PreparedStatement pstmt1 = null;        PreparedStatement pstmt2 = null;        try {            //1.获取连接            conn = jdbcutils.getConnection();            //开启事务            conn.setAutoCommit(false);            //2.定义sql            //2.1 张三 - 500            String sql1 = "update account set balance = balance - ? where id = ?";            //2.2 李四 + 500            String sql2 = "update account set balance = balance + ? where id = ?";            //3.获取执行sql对象            pstmt1 = conn.prepareStatement(sql1);            pstmt2 = conn.prepareStatement(sql2);            //4. 设置参数            pstmt1.setDouble(1,500);            pstmt1.setInt(2,1);            pstmt2.setDouble(1,500);            pstmt2.setInt(2,2);            //5.执行sql            pstmt1.executeUpdate();            // 手动制造异常            //int i = 3/0;            pstmt2.executeUpdate();            //提交事务            conn.commit();        } catch (Exception e) {            //事务回滚            try {                if(conn != null) {                    conn.rollback();                }            } catch (SQLException e1) {                e1.printStackTrace();            }            e.printStackTrace();        }finally {            jdbcutils.release(conn,pstmt1,null);            jdbcutils.release(null,pstmt2,null);        }    }}

正常结果如下:

如果手动制造异常,则事务回滚,转账失败。

最后,介绍一下数据库连接池JDBC Template。数据库连接池就是一个容器,存放数据库连接对象,用户访问数据库时直接从连接池中获取数据库连接对象,访问完再归还给容器。使用数据库连接池可以解决资源,提高访问效率。

连接池常用的有C3P0和Druid。两者的使用都要导入jar包。

C3P0:先导入两个jar包,然后在src目录下定义配置文件:

c3p0.properties 或者 c3p0-config.xml。

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

Druid:先导入jar包 ,在任意目录下定义druid.properties配置文件。

#驱动加载driverClassName=com.mysql.jdbc.Driver#注册驱动url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false#连接数据库的用户名username=root#连接数据库的密码password=root#属性类型的字符串,通过别名的方式配置扩展插件, 监控统计用的stat 日志用log4j 防御sql注入:wallfilters=stat#初始化时池中建立的物理连接个数。initialSize=2#最大的可活跃的连接池数量maxActive=300#获取连接时最大等待时间,单位毫秒,超过连接就会失效。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降, 如果需要可以通过配置useUnfairLock属性为true使用非公平锁。maxWait=60000#连接回收器的运行周期时间,时间到了清理池中空闲的连接,testWhileIdle根据这个判断timeBetweenEvictionRunsMillis=60000minEvictableIdleTimeMillis=300000#用来检测连接是否有效的sql,要求是一个查询语句。validationQuery=SELECT 1#建议配置为true,不影响性能,并且保证安全性。 申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis, 执行validationQuery检测连接是否有效。testWhileIdle=true#申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。设置为falsetestOnBorrow=false#归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能,设置为flasetestOnReturn=false#是否缓存preparedStatement,也就是PSCache。poolPreparedStatements=false#池中能够缓冲的preparedStatements语句数量maxPoolPreparedStatementPerConnectionSize=200
//1.加载配置文件Properties pro = new Properties();InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");pro.load(is);//2.获取连接池对象DataSource ds = DruidDataSourceFactory.createDataSource(pro);//3.获取连接Connection conn = ds.getConnection();

同样的,为了简化书写,编写JDBCUtils来加载配置文件,初始化连接对象,释放资源。

public class JDBCUtils {    //1.定义成员变量 DataSource    private static DataSource ds ;    static{        try {            //1.加载配置文件            Properties pro = new Properties();            pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));            //2.获取DataSource            ds = DruidDataSourceFactory.createDataSource(pro);        } catch (IOException e) {            e.printStackTrace();        } catch (Exception e) {            e.printStackTrace();        }    }    //获取连接    public static Connection getConnection() throws SQLException {        return ds.getConnection();    }    //释放资源    public static void close(ResultSet rs , Statement stmt, Connection conn){        if(rs != null){            try {                rs.close();            } catch (SQLException e) {                e.printStackTrace();            }        }        if(stmt != null){            try {                stmt.close();            } catch (SQLException e) {                e.printStackTrace();            }        }        if(conn != null){            try {                conn.close();//归还连接            } catch (SQLException e) {                e.printStackTrace();            }        }    }   //获取连接池方法    public static DataSource getDataSource(){        return  ds;    }}

这样,我们就可以方便高效的使用JDBC了。

最后,还有一个关于JDBC的知识点,前面说过Spring可以集成Mybatis,同样,Spring也可以集成JDBC!会在后面单独写一章。

jdbc获取一行字符串_JDBC基础相关推荐

  1. jdbc获取clob图片_jdbc方式读取oracle的clob字段实例

    可能大家也都习惯了spring和hibernate对CLOB字段的处理,在spring中配置clob的oracle处理句柄,在hibernate中配置映射类型,然后就可以很轻松的以String 的形式 ...

  2. j1_12_01.实现手机号计数功能关键算法.传入字符串数组,获取符合手机号格式的字符串.从键盘接收一行字符串,字符串中只包含数字和空格,统计其中所有的手机号码数量。

    import java.util.Scanner;/*** 任务一:实现手机号计数功能关键算法并绘制流程图(30 分) 从键盘接收一行字符串,字符串中只包含数字和空格,统计其中所有的手机号码数量. 比 ...

  3. java class 字符串_java基础知识四 math类 字符 字符串 控制台输入输出 StringBuilder与StringBuffer...

    第四章:数学函数.字符和字符串 math类 Math是final类:在java.lang.Math中,所有数学函数都是静态方法 在一个java程序中,java.lang包中的所有类是隐式导入的. 三角 ...

  4. VB 提取TextBox 文本框中指定一行字符串

    这是使用EM_GETLINE message来做,比较奇特的是lParam是指向一个字串所在的位置, 但是该字串传入时,前两个Byte要存该字串允许的最大长度. '以下在Form需一个TextBox, ...

  5. C++ getline():从文件中读取一行字符串

    C++ getline():从文件中读取一行字符串 前一节中,详细介绍了如何使用 getline() 方法从 cin 输入流缓冲区中读取一行字符串.在此基础上,getline() 方法还适用于读取指定 ...

  6. php 获取一串随机字符串,php获取随机字符串的几种方法

    方法一:shuffle函数(打乱数组)和mt_rand函数(生成随机数,比rand速度快四倍) /** * 获得随机字符串 * @param $len 需要的长度 * @param $special ...

  7. 输入输出一行字符串(应声虫)

    目录 一.解题思路 二.解题的三个方案 1.用字符数组解题 2.用getchar()函数解题 3.用gets()函数来解题 一.解题思路 传说唐.宋时有人患怪病,腹内生虫:人说话,虫即小声应之,是为应 ...

  8. Swift3.0语言教程获取C字符串

    Swift3.0语言教程获取C字符串 Swift3.0语言教程获取C字符串,为了让Swift和C语言可以实现很好的交互,开发者可以使用NSString的cString(using:)方法在指定编码格式 ...

  9. shell实例第2讲:获取随机字符串

    获取随机字符串常用三种方法: 方法一: echo $RANDOM |md5sum |cut -c 1-8 说明: (1)RANDOM会产生随机数,经过md5sum,再通过cut截取第一位到第八位的字符 ...

最新文章

  1. [BZOJ2527]Meteors
  2. 如何再造一个百度贴吧兼谈如何改造园子的团队
  3. IIS 7 应用程序池自动回收关闭的解决方案
  4. centos下添加的端口不能访问(防火墙关闭)
  5. Zookeeper基于Java 访问-节点权限设置
  6. 计算机基础扎实,到底是说什么?
  7. 基于python的HOG+SVM目标检测算法实现
  8. 科普!程序员分不清万圣节和圣诞节?
  9. 数据库_初学语句 in的用法
  10. 两波形相位差的计算值_如何将您的计算机用作任意波形发生器
  11. 软件测试的基础知识(二)
  12. android定时截取屏幕内容,Android 截取手机屏幕两种实现方案解析
  13. java 开根号函数_java如何开根号?
  14. 爬取12306验证码图片
  15. matlab字符识别ocr,OCR字符识别 matlab
  16. div绑定onblur事件
  17. 作为一个新手程序员该如何成长
  18. snes9x 源码_仅64kb的SNES游戏如何制作优美的音乐
  19. WMI与CIM的区别
  20. 1-1 机器学习和深度学习综述

热门文章

  1. linux7开启ntp服务,【NTP】CentOS7.2配置NTP服务
  2. 自己建服务器 语音盒子_使用Mumble搭建私人语音服务器
  3. 深入理解多重采样(Multisampling)
  4. Android开发之recyclerview布局加载不全的问题
  5. 关于Android studio 3.0 Failure [INSTALL_FAILED_TEST_ONLY]安装失败的问题
  6. php cap,PHP ImagickDraw setStrokeLineCap()用法及代码示例
  7. jsp获取java数组长度_数组 – 如何在java jsp中获取数组列表大小?
  8. php crc32 作用,php的crc32函数使用时需要注意的问题(不然就是坑)
  9. 查数估获近千万元融资 ,用科技为金融赋能
  10. 【网络基础】 PAUSE帧总结