JDBC基本操作(Statement,PreparedStatement,Connection,Transaction等)

13 篇文章 0 订阅

JDBC与数据库连接,查询

package jdbc;

import java.sql.*;//数据库相关库

public class TestJDBC {

    public static void main(String[] args) {
        final String DBDRIVER="org.mariadb.jdbc.Driver";//数据库连接驱动,对于每一种数据库都不一样
        final String DBURL="jdbc:mariadb://localhost:3306/test";//数据库地址,3306是端口,test是数据库名
        final String DBUSER="root";//数据库用户名
        final String DBPASSWORD="root";//数据库密码

        Connection conn=null;//数据库连接对象
        Statement statement=null;//数据库SQL语言执行语句
        ResultSet rs=null;//返回数据结果集合,包含着只想数据的指针

        try {
            Class.forName(DBDRIVER);//反射机制初始化对象
            conn=DriverManager.getConnection(DBURL,DBUSER,DBPASSWORD);//设置数据库连接
            statement=conn.createStatement();//statement创建
            rs=statement.executeQuery("SELECT * from test1");//statement执行查询语句得到结果传递给rs,test1是表名,下同
            while(rs.next()){//ResultSet指针初始指向在数据集第一行的前面,运用.next()方法依次向下查询
                System.out.println(rs.getString("name"));//根据字段名获取数据,并以String类型存入内存
            }   
        } catch (ClassNotFoundException e) {//Driver对象创建时引入的错误抛出
            e.printStackTrace();
        }catch(SQLException e){//Connection对象创建时引入的错误抛出
            e.printStackTrace();
        }finally{//良好的变成习惯,在使用过数据库操作之后,将ResultSet,Statement,Connection对象都清空
            try {
                if(rs!=null){
                    rs.close();
                }
                if(statement!=null){
                    statement.close();
                }
                if(conn!=null){
                    conn.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }

}

所有实验使用数据库如下:
实验数据库
JDBC插入数据

package jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestDML {

    public static void main(String[] args) {
        final String DBDRIVER="org.mariadb.jdbc.Driver";
        final String DBURL="jdbc:mariadb://localhost:3306/test";
        final String DBUSER="root";
        final String DBPASSWORD="root";

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

        try {
            Class.forName(DBDRIVER);
            conn=DriverManager.getConnection(DBURL,DBUSER,DBPASSWORD);
            statement=conn.createStatement();
            //和上一个唯一不同是这里使用的是插入操作
            String sql="insert into test1 values (4,'James')";//手工写入完整SQL语句
            statement.executeUpdate(sql);//statement执行SQL语句

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

从传入参数获取数据的JDBC数据插入

package jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestDML2 {

    public static void main(String[] args) {
        if(args.length!=2){//程序输入参数判断
            System.out.println("Parameter Error! Please input again!");
            System.exit(-1);
        }

        int num=0;
        try{
            num=Integer.parseInt(args[0]);//将第一个传入参数强制转换为Int类型存入num
        }catch(NumberFormatException e){//严谨编程,捕捉数据格式错误
            e.printStackTrace();
            System.out.println("Number Format Error");
            System.exit(-1);
        }
        String name=args[1];//输入参数都是字符串,不需要再转换

        final String DBDRIVER="org.mariadb.jdbc.Driver";
        final String DBURL="jdbc:mariadb://localhost:3306/test";
        final String DBUSER="root";
        final String DBPASSWORD="root";

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

        try {
            Class.forName(DBDRIVER);
            conn=DriverManager.getConnection(DBURL,DBUSER,DBPASSWORD);
            statement=conn.createStatement();
            //使用传入参数的方式,获取需要的插入的数据
            //可以发现这种手工组合SQL语言的方式非常繁琐,容易出错
            String sql="insert into test1 values ("+num+",'"+name+"')";
            System.out.println(sql);//在调试的时候,可以将SQL语句输出进行检查,或者试验在数据库中执行
            statement.executeUpdate(sql);//执行更新数据库

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

JDBC预设语句PreparedStatement

package jdbc;

import java.sql.*;

public class TestPreparedStatement {

    public static void main(String[] args) {
        if(args.length!=2){
            System.out.println("Paramenter Error, please input again!");
            System.exit(-1);
        }

        int num=0;
        String name=null;
        try{
            num=Integer.parseInt(args[0]);
        }catch(NumberFormatException e){
            e.printStackTrace();
            System.exit(-1);
        }
        name=args[1];

        final String DBDRIVER="org.mariadb.jdbc.Driver";
        final String DBURL="jdbc:mariadb://localhost:3306/test";
        final String DBUSER="root";
        final String DBPASSWORD="root";

        Connection conn=null;
        PreparedStatement pStatement=null;
        try {
            Class.forName(DBDRIVER);
            conn=DriverManager.getConnection(DBURL,DBUSER,DBPASSWORD);
            //上一个通过手工拼接SQL语句的操作非常的繁琐,有可以解决的方式
            //使用PreparedStatement,预先设置好语句的格式,然后一次设置待定的参数
            pStatement=conn.prepareStatement("insert into test1 values (?,?)");//?是两个待定的参数
            pStatement.setInt(1, num);//将第一个?位置设置为num
            pStatement.setString(2, name);//将第二个?位置设置为name
            pStatement.executeUpdate();//执行操作

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }catch(SQLException e){
            e.printStackTrace();
        }finally{
            try {
                if(conn!=null){
                    pStatement.close();
                    conn.close();
                }
                name=null;
                num=0;
            } catch (SQLException e) {
                e.printStackTrace();
            }   
        }   
    }
}

JDBC批量操作Batch

package jdbc;

import java.sql.*;
public class TestBatch {

    public static void main(String[] args) throws Exception{
        //这个程序没有写像之前那么严谨的try/catch程序块,是为了更清晰地表现逻辑
        Connection conn=null;
        PreparedStatement ps=null;
        Class.forName("org.mariadb.jdbc.Driver");
        conn=DriverManager.getConnection("jdbc:mariadb://localhost:3306/test", "root", "root");
        ps=conn.prepareStatement("insert into test1 values (?,?)");
        //实际工程经常会有大量的数据增删改查,一条一条数据的操作自然不行
        //需要批量的操作,JDBC中使用Batch
        ps.setInt(1, 3);
        ps.setString(2, "Iverson");
        ps.addBatch();//将组装好的PreparedStatement存入Batch

        ps.setInt(1, 1);
        ps.setString(2, "McGrady");
        ps.addBatch();

        ps.setInt(1,3);
        ps.setString(2, "Wade");
        ps.addBatch();

        ps.executeBatch();//执行Batch,执行三条数据库插入
        ps.close();
        conn.close();   
    }
}

JDBC事务

package jdbc;

import java.sql.*;

public class TestTransaction {

    public static void main(String[] args) {

        Connection conn=null;
        Statement statement=null;
        try {
            Class.forName("org.mariadb.jdbc.Driver");
            conn=DriverManager.getConnection("jdbc:mariadb://localhost:3306/test", "root", "root");
            //有些数据库操作时必须绑定起来进行的,例如账户转账,从一个账户中扣除,另一个账户中存入,两个操作必须同时成功,或者同时失败,否则会造成数据错误
            //对于这种绑定在一起的数据库操作,称之为一个事务
            //JDBC中,首先要设置连接不是自动提交的,默认状态是自动提交
            conn.setAutoCommit(false);//可以把这句话注释掉,然后在下面其中一句插入语句中制造一点小错误,来试验效果

            statement=conn.createStatement();
            statement.addBatch("insert into test1 values (21,'Duncan')");
            statement.addBatch("insert into test1 values (13,'Nash')");
            statement.executeBatch();//执行Batch
            //注释与不注释实验看区别
            conn.commit();//提交事务
            conn.setAutoCommit(true);//事务执行完,将自动提交设置为true

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                if(conn!=null){
                    conn.rollback();
                    conn.setAutoCommit(true);
                }
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        }finally{
            try {
                if(statement!=null){
                    statement.close();
                    statement=null;
                }
                if(conn!=null){
                    conn.close();
                    conn=null;
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }   
    }
}

JDBC处理可滚动的数据结果集

package jdbc;

import java.sql.*;

public class TestScroll {

    public static void main(String[] args) {

        Connection conn=null;
        Statement statement=null;
        ResultSet rs=null;
        try {
            Class.forName("org.mariadb.jdbc.Driver");
            conn=DriverManager.getConnection("jdbc:mariadb://localhost:3306/test", "root", "root");
            //http://www.cnblogs.com/bukudekong/archive/2011/06/22/2086528.html
            statement=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
            //设置回滚模式,回滚模式,不仅可以使用.next()进行数据轮询,还可以使用以下功能,实现更灵活的数据结果操作
            rs=statement.executeQuery("select * from test1");
            rs.next();
            System.out.println(rs.getInt("id"));
            System.out.println(rs.getString("name"));

            rs.last();//最后一行
            System.out.println(rs.getInt("id"));
            System.out.println(rs.getString("name"));
            System.out.println(rs.isLast());//是否是最后一行
            System.out.println(rs.isAfterLast());//是否在最后一行之后
            System.out.println(rs.getRow());//当前行数

            rs.previous();//前一行
            System.out.println(rs.getInt("id"));
            System.out.println(rs.getString("name"));
            System.out.println(rs.isLast());
            System.out.println(rs.getRow());//当前行数

            rs.absolute(6);//绝对位置,第6行
            System.out.println(rs.getInt("id"));
            System.out.println(rs.getString("name"));

            rs.first();//第一行
            System.out.println(rs.getInt("id"));
            System.out.println(rs.getString("name"));
            System.out.println(rs.isFirst());



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

JDBC处理可更新的数据集

package jdbc;

import java.sql.*;

public class TestUpdatetable {

    public static void main(String[] args) {

        Connection conn=null;
        Statement statement=null;
        ResultSet rs=null;
        try {
            Class.forName("org.mariadb.jdbc.Driver");
            conn=DriverManager.getConnection("jdbc:mariadb://localhost:3306/test", "root", "root");
            //http://www.cnblogs.com/bukudekong/archive/2011/06/22/2086528.html
            statement=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
            rs=statement.executeQuery("select * from test1");
            //updatetable可以使java逻辑和数据库实时关联,不需要提交就可以实时更改数据
            //但这需要数据库驱动支持CONCUR_UPDATABLE模式
            //但貌似并不是所有数据库都支持,mariadb貌似不支持
            //猜想应该是处于安全性的考虑,大的自由度也带来了较大的风险
            rs.next();
            rs.updateInt("id", 8);
            rs.updateRow();//更新行数据
        }catch(ClassNotFoundException e){
            e.printStackTrace();
        }catch(SQLException e){
            e.printStackTrace();
        }finally{
            try {
                if(rs!=null){
                    rs.close();
                    rs=null;
                }
                if(statement!=null){
                    statement.close();
                    statement=null;
                }
                if(conn!=null){
                    conn.close();   
                    conn=null;
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果如下,说明不支持实时更新

本文是参考尚学堂马士兵的JDBC教学视频编写得来,讲得很清楚,适合初学。

新增:

深入

1 、 PreparedStatement 接口继承 Statement , PreparedStatement 实例包含已编译的 SQL 语句,所以其执行速度要快于 Statement 对象。
2 、作为 Statement 的子类, PreparedStatement 继承了 Statement 的所有功能。三种方法
execute 、 executeQuery 和 executeUpdate 已被更改以使之不再需要参数

3 、在 JDBC 应用中 , 如果你已经是稍有水平开发者 , 你就应该始终以 PreparedStatement 代替
Statement. 也就是说 , 在任何时候都不要使用 Statement.
基于以下的原因 :
一 . 代码的可读性和可维护性 .
虽然用 PreparedStatement 来代替 Statement 会使代码多出几行 , 但这样的代码无论从可读性还是可维护性上来说 . 都比直接用 Statement 的代码高很多档次 :
stmt.executeUpdate(“insert into tb_name (col1,col2,col2,col4) values (‘”+var1+”’,’”+var2+”’,”+var3+”,’”+var4+”’)”);//stmt 是 Statement 对象实例

perstmt = con.prepareStatement(“insert into tb_name (col1,col2,col2,col4) values (?,?,?,?)”);
perstmt.setString(1,var1);
perstmt.setString(2,var2);
perstmt.setString(3,var3);
perstmt.setString(4,var4);
perstmt.executeUpdate(); //prestmt 是 PreparedStatement 对象实例

不用我多说 , 对于第一种方法 . 别说其他人去读你的代码 , 就是你自己过一段时间再去读 , 都会觉得伤心 .

PreparedStatement 尽最大可能提高性能 .
语句在被 DB 的编译器编译后的执行代码被缓存下来 , 那么下次调用时只要是相同的预编译语句就不需要编译 , 只要将参数直接传入编译过的语句执行代码中 ( 相当于一个涵数 ) 就会得到执行 . 这并不是说只有一个 Connection 中多次执行的预编译语句被缓存 , 而是对于整个 DB 中 , 只要预编译的语句语法和缓存中匹配 . 那么在任何时候就可以不需要再次编译而可以直接执行 . 而 statement 的语句中 , 即使是相同一操作 , 而由于每次操作的数据不同所以使整个语句相匹配的机会极小 , 几乎不太可能匹配 . 比如 :
insert into tb_name (col1,col2) values (‘11’,’22’);
insert into tb_name (col1,col2) values (‘11’,’23’);
即使是相同操作但因为数据内容不一样 , 所以整个个语句本身不能匹配 , 没有缓存语句的意义 . 事实是没有数据库会对普通语句编译后的执行代码缓存 .

当然并不是所以预编译语句都一定会被缓存 , 数据库本身会用一种策略 , 比如使用频度等因素来决定什么时候不再缓存已有的预编译结果 . 以保存有更多的空间存储新的预编译语句 .

三 . 最重要的一点是极大地提高了安全性 .

即使到目前为止 , 仍有一些人连基本的恶义 SQL 语法都不知道 .
String sql = “select * from tb_name where name= ‘”+varname+”’ and passwd=’”+varpasswd+”’”;
如果我们把 [’ or ‘1’ = ‘1] 作为 varpasswd 传入进来 . 用户名随意 , 看看会成为什么 ?

select * from tb_name = ’ 随意 ’ and passwd = ” or ‘1’ = ‘1’;
因为 ‘1’=’1’ 肯定成立 , 所以可以任何通过验证 . 更有甚者 :
把 [‘;drop table tb_name;] 作为 varpasswd 传入进来 , 则 :
select * from tb_name = ’ 随意 ’ and passwd = ”;drop table tb_name; 有些数据库是不会让你成功的 , 但也有很多数据库就可以使这些语句得到执行 .

而如果你使用预编译语句 . 你传入的任何内容就不会和原来的语句发生任何匹配的关系 . 只要全使用预编译语句 , 你就用不着对传入的数据做任何过虑 . 而如果使用普通的 statement, 有可能要对 drop,; 等做费尽心机的判断和过虑 .

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值