18.JDBC开发(1)(我的JavaEE笔记)

一、JDBC简介

Sun公司为了简化、统一对数据库的操作,定义了一套java操作数据库的规范,称之为JDBC。

  • 注意:JDBC只是一个规范,一套对数据库操作的接口,其是由sun公司定义的,所以我们在导入相关包时都是导入javaSE中的包,而不是导入相关的驱动中的包,那只是对sun公司JDBC的实现。
  • JDBC主要由两个包组成:java.sqljavax.sql。开发jdbc应用需要以上两个包的支持外,还需要导入相应的jdbc的数据库实现(即驱动)。而java.sqljavax.sql已经称为javaSE的规范,所以现在不需要导入了。只需要导入相关的驱动就可以了。

二、第一个JDBC程序

2.1搭建试验环境

  • 1.在mysql中创建一个库,并创建user表和插入表的数据。
create database day14;
use day14;
create table user(
    id int primary key auto_increment,
    name varchar(40),
    password varchar(40),
    email varchar(60),
    birthday date
)character set utf8 collate utf8_general_ci;
insert into user(name,password,email,birthday) values('zs','123456','zs@sina.com','1980-12-04');
insert into user(name,password,email,birthday) values('lisi','123456','lisi@sina.com','1981-12-04');
  • 2.新建一个java工程(day14),并导入相关数据库驱动。
    驱动是:mysql-connector-java-5.1.37-bin.jar

Demo1.java

package cn.itcast.demo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Demo1 {

    public static void main(String[] args) throws SQLException {
        String url = "jdbc:mysql://localhost:3305/day14";
        String username = "root";
        String password = "walp1314";
        
        //1.加载驱动
        DriverManager.registerDriver(new com.mysql.jdbc.Driver());
        
        //2.获取与数据库的链接
        Connection connection = DriverManager.getConnection(url, username, password);
        
        //3.获取用于向数据库发送sql语句的statement对象
        Statement st = connection.createStatement();
        
        //4.向数据库发送sql语句,并获取代表结果集的ResultSet对象
        String sql = "select id, name, password, email, birthday from user";
        ResultSet result = st.executeQuery(sql);
        
        //5.取出结果集的数据
        while(result.next()){
            System.out.println("id= " + result.getObject("id"));
            System.out.println("name= " + result.getObject("name"));
        }
        
        //6.关闭链接,释放资源
        result.close();
        st.close();
        connection.close();

    }
}

2.2程序详解

2.2.1 DriverManager

  • jdbc程序中的DriverManager用于加载驱动,并创建与数据库的连接,这个API的常用方法:
DriverManager.registerDriver(new Driver());
DriverManager.getConnection(url,user,password);
  • 注意:在实际开发中并不推荐采用registerDriver方法注册驱动。原因有二:
    一是通过Driver的源代码可以看到,如果采用此种方式,会导致驱动程序注册两次,也就是在内存中会有两个Driver对象。
    二是程序依赖mysql的api,脱离这个api的jar包,程序将无法编译,这样不便于切换底层数据库。
    推荐方式:Class.forName("com.mysql.jdbc.Driver");采用此种方式不会导致驱动对象在内存中重复出现,并且采用此种方式,程序仅仅需要一个字符串,不需要依赖具体的驱动,程序的灵活性更高。
    同样也不建议采用具体的驱动类型指向getConnection方法返回的connection对象,比如:
conn = (com.mysql.jdbc.Connection) DriverManager.getConnection(url, username, password);

2.2.2 数据库URL

  • url用于标识数据库的位置,程序员通过url地址告诉jdbc程序连接哪个数据库,url的写法为:
    jdbc:mysql://localhost:3305/day14?参数名:参数值
    问号后面可以带上编码信息,如果不带,则根据数据库的编码自动指定。
  • 常用数据库URL地址的写法:
    Oracle写法:jdbc:oracle:thin:@localhost:1521:sid
    SqlServer写法:jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=sid
    MySql写法:jdbc:mysql://localhost:3305/day14
  • 常用属性:useUnicode=true&characterEncoding=UTF-8

2.2.3 Connection

  • jdbc程序中的Connection用于代表数据库的连接,Connection是数据库编程中最重要的一个对象,客户端与数据库所有交互都是通过Connection对象完成的,这个对象的常用方法:
    createStatement():创建向数据库发送sql的statement对象。
    prepareStatement(sql):创建向数据库发送预编译sql的PrepareSatement对象。
    prepareCall(sql):创建执行存储过程的callableStatement对象。
    setAutoCommit(boolean autoCommit):设置事务是否自动提交。
    commit():在链接上提交事务。
    rollback():在此链接上回滚事务。

2.2.4 Statement

  • jdbc程序中的Statement对象用于向数据库发送sql语句,Statement对象常用方法:
    executeQuery(String sql):用于向数据发送查询语句。
    executeUpdate(String sql):用于向数据库发送insert、update或delete语句
    execute(String sql):用于向数据库发送任意sql语句
    addBatch(String sql):把多条sql语句放到一个批处理中。
    executeBatch():向数据库发送一批sql语句执行。
  • 注意:这个addBatch是先将多条语句添加到Statement对象中,然后使用executeBatch方法一起执行。

2.2.5 ResultSet

  • jdbc程序中的ResultSet用于代表sql语句的执行结果。ResultSet封装执行结果时,采用的类似于表格的方式。ResultSet对象维护了一个指向表格数据行的游标,初始的时候,游标在第一行之前,调用ResultSet.next()方法,可以使游标指向具体的数据行,进行调用方法获取该行的数据。
  • ResultSet既然是用于封装执行结果的,所以该对象提供的都是用于获取数据的get方法:
    获取任意类型的数据
getObject(int index)
getObject(string columnName)

获取指定类型的数据

getString(int index)
getString(String columnName)
  • 提问:数据库中列的类型是varchar,获取该列的数据调用什么方法?int类型呢?bigint类型呢?Boolean类型?
    常用数据类型转换表
sql类型 jdbc对应的方法 返回类型
BIT(1) BIT(N) getBoolean getBytes() boolean byte[]
TINYINT getByte() byte
SMALLINT getShort() short
INT getInt() int
BIGINT getLong() long
CHAR,VARCHAR,LONGVARCHAR getString() String
TEXT(clob) BLOB getClob() getBlob() Clob Blob
DATE getDate() java.sql.Date
TIME getTime() java.sql.Time
TIMESTAMP getTimestamp() java.sql.Timestamp
  • ResultSet还提供了对结果进行滚动的方法:
    next():移动到下一行
    previous():移动到前一行
    absolute(int row):移动到指定行
    beforeFirst():移动resultSet的最前面。
    afterLast():移动到resultSet的最后面。
    注意:开始时指向表头,使用一次next才指向第一条数据,而使用afterLast方法之后指向表尾,这样使用previous方法才执行最后一条数据。

2.2.6 释放资源

  • jdbc程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象,这些对象通常是ResultSet、Statement和Connection对象。
  • 特别是Connection对象,它是非常稀有的资源,用完后必须马上释放,如果不能及时、正确的关闭,很容易导致宕机。其使用原则是尽量晚创建,尽量早的释放。
  • 为确保资源释放代码能运行,资源释放代码也一定要放在finally语句中。

对上面例子进行修正:Demo.java

package cn.itcast.demo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Demo2 {

    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        String url = "jdbc:mysql://localhost:3305/day14";
        String username = "root";
        String password = "walp1314";
        
        Connection connection = null;
        Statement statement = null;
        ResultSet result = null;
        try{
            //1.加载驱动(推荐)
            Class.forName("com.mysql.jdbc.Driver");
            
            //2.获取与数据库的链接
            connection = DriverManager.getConnection(url, username, password);
            
            //3.获取用于向数据库发送sql语句的statement对象
            statement = connection.createStatement();
            
            //4.向数据库发送sql语句,并获取代表结果集的ResultSet对象
            String sql = "select id, name, password, email, birthday from user";
            result = statement.executeQuery(sql);
            
            //5.取出结果集的数据
            while(result.next()){
                System.out.println("id= " + result.getObject("id"));
                System.out.println("name= " + result.getObject("name"));
            }
        }finally{
        
            //6.关闭链接,释放资源
            //方式一:
            /*if(result != null){
                try {
                    result.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if(statement != null){
                try {
                    statement.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if(connection != null){
                try {
                    connection.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }*/
            //方式二:
            if(result != null){
                try {
                    result.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally{
                    if(statement != null){
                        try {
                            statement.close();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }finally{
                            if(connection != null){
                                try {
                                    connection.close();
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                }
            }
        }

    }

}

说明:

  • 我们在使用jdbc的时候必须要保证最后资源能够释放,不管前面程序是否运行正确。于是我们将资源释放的代码放在finally块中,这样就保证了不管发生什么情况下资源都会被释放。上面我们提供了两种释放资源的方式,因为每一个关闭语句都可能会产生异常,所以关闭比较麻烦。
  • finally块中的语句在JVM(exit(1))或是死循环时是不会执行的,其他情况下都会执行,同时注意是在return语句之前执行。

三、使用JDBC对数据库进行CRUD

从之前的例子中我们可以发现在每次使用数据库都需要链接数据库和释放资源,我们可以将这些重复的代码统一放在一个工具类中。同时对于数据库中需要用到的一些资源,比如url、用户名、密码等我们直接写死在程序中也不便于日后维护,于是我们将这些资源放在一个配置文件中。

src/db.properties

### MySQL
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3305/day14
username=root
password=walp1314

### Oracle
#driver=oracle.jdbc.driver.OracleDriver
#url=jdbc:oracle:thin:@localhost:1521:orcl
#username=root
#password=walp1314

JdbcUtils.java

package cn.itcast.utils;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

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{
            //获取资源文件,这里我们的资源文件放在src下
            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){
            throw new ExceptionInInitializerError(e);
        }
    }
    //获得数据库链接
    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();
            }
        }
    }
}

测试:Demo3.java

package cn.itcast.demo;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import org.junit.Test;
import cn.itcast.utils.JdbcUtils;

public class Demo3 {
    
    //数据库插入
    @Test
    public void insert(){
        Connection connection = null;
        Statement statement = null;
        ResultSet result = null;
        try {
            //通过工具类获得数据库的链接
            connection = JdbcUtils.getConnection();
            statement = connection.createStatement();
            String sql = "insert into user(id, name, password, email, birthday) "
                    + "values(4, 'xxx', '12', 'xx@sina.com', '1998-09-09')";
            //下面的返回值表示影响了数据库多少行
            int num = statement.executeUpdate(sql);
            if(num  > 0){
                System.out.println("插入成功");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            //通过工具类释放资源
            JdbcUtils.release(connection, statement, result);
        }
    }
    
    //删除操作
    @Test
    public void delete(){
        Connection connection = null;
        Statement statement = null;
        ResultSet result = null;
        try {
            //通过工具类获得数据库的链接
            connection = JdbcUtils.getConnection();
            statement = connection.createStatement();
            String sql = "delete from user where id = 4";
            int num = statement.executeUpdate(sql);
            if(num > 0){
                System.out.println("删除成功");
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            //通过工具类释放资源
            JdbcUtils.release(connection, statement, result);
        }
    }
    
    //修改操作
    @Test
    public void update(){
        Connection connection = null;
        Statement statement = null;
        ResultSet result = null;
        try {
            //通过工具类获得数据库的链接
            connection = JdbcUtils.getConnection();
            statement = connection.createStatement();
            String sql = "update user set name='tom', email='tom@sina.com' where id = 2";
            int num = statement.executeUpdate(sql);
            if(num > 0){
                System.out.println("修改成功");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            //通过工具类释放资源
            JdbcUtils.release(connection, statement, result);
        }
    }
    
    //查找操作
    @Test
    public void find(){
        Connection connection = null;
        Statement statement = null;
        ResultSet result = null;
        try {
            //通过工具类获得数据库的链接
            connection = JdbcUtils.getConnection();
            statement = connection.createStatement();
            String sql = "select * from user where id = 1";
            result = statement.executeQuery(sql);
            if(result.next()){
                System.out.println(result.getString("name"));
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            //通过工具类释放资源
            JdbcUtils.release(connection, statement, result);
        }
    }
}

注意:在以后的开发中我们不会再使用Statement这个对象,而是使用其子类PreparedStatement,同时这个对象可以防范sql注入,相关使用方法请看笔记17.2 。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容

  • JDBC概述 在Java中,数据库存取技术可分为如下几类:JDBC直接访问数据库、JDO技术、第三方O/R工具,如...
    usopp阅读 3,526评论 3 75
  • 本节介绍Statement接口及其子类PreparedStatement和CallableStatement。 它...
    zlb阅读 1,132评论 0 0
  • JDBC简介 SUN公司为了简化、统一对数据库的操作,定义了一套Java操作数据库的规范,称之为JDBC。JDBC...
    奋斗的老王阅读 1,502评论 0 51
  • 本人的环境为Myeclipse10、MySQL5.7.15 本文包括:简介JDBC编程步骤打通数据库程序详解—Dr...
    廖少少阅读 3,923评论 7 39
  • 北京-果汁贺-互联网-摄影3888 2017.6 北京 iPhone6p 无 跟新朋友吹着空调吃火锅,包场 幸福
    果汁贺阅读 189评论 2 0