JDBC编程

SQL语句主要分为五种:

1. 查询语句:主要由select关键字完成,查询语句是SQL语句中最复杂、功能最丰富的语句;

2. DML(Data Manipulation Language,数据操作语言):包含insert、update、delete

3. DDL(Data Definition Language, 数据定义语言):包含create、 alter、drop、truncate

4. DCL(Data Control Language,数据控制语言):包含grant 、revoke

5. 事务控制语句: commit、rollback、savepoint

JDBC编程步骤:

1. 加载数据库驱动。通过Class类的forName()静态方法来加载驱动

Class.forName(driverClass)

2. 通过DriverManager获取数据库连接Connection对象。

DriverManager.getConnection(String url,String user,String pass)

3. 通过Connection对象创建Statement对象。创建Statement有三种方法。

  • createStatement(): 创建基本的Statement对象
  • prepareStatement(String sql): 根据传入的SQL语句创建预编译的Statement对象
  • prepareCall(String sql): 根据传入的SQL语句创建CallableStatement对象。

4. 使用Statement执行SQL语句。

execute(): 可以执行任何SQL语句,但比较麻烦,在不清SQL语句类型时,只能使用这个方法。

executeUpdate():主要用于执行DML和DDL语句。执行DML语句返回受SQL语句影响的行数,执行DDL语句返回0。

executeQuery():只能执行查询语句,执行后返回代表查询结果的ResultSet对象。

5. 操作结果集。有两类方法来操作结果集:

  • next()、 previous()、 first()、 last()、 beforeFirst()、 afterLast()、 absolute()
  • getXxx()方法获取记录指针指向行、特定列的值。

6. 回收数据库资源,包括ResultSet、Statement和Connection等资源。

例子:

import java.sql.*;

public class ConnMySql
{
    public static void main(String[] args) throws Exception
    {
        // 1.加载驱动,使用反射的知识,现在记住这么写。
        Class.forName("com.mysql.jdbc.Driver");
        try(
            // 2.使用DriverManager获取数据库连接,
            // 其中返回的Connection就代表了Java程序和数据库的连接
            // 不同数据库的URL写法需要查驱动文档知道,用户名、密码由DBA分配
            Connection conn = DriverManager.getConnection(
                "jdbc:mysql://127.0.0.1:3306/select_test"
                , "root" , "32147");
            // 3.使用Connection来创建一个Statment对象
            Statement stmt = conn.createStatement();
            // 4.执行SQL语句
            /*
            Statement有三种执行sql语句的方法:
            1 execute 可执行任何SQL语句。- 返回一个boolean值,
              如果执行后第一个结果是ResultSet,则返回true,否则返回false
            2 executeQuery 执行Select语句 - 返回查询到的结果集
            3 executeUpdate 用于执行DML语句。- 返回一个整数,
              代表被SQL语句影响的记录条数
            */
            ResultSet rs = stmt.executeQuery("select s.* , teacher_name"
                + " from student_table s , teacher_table t"
                + " where t.teacher_id = s.java_teacher"))//在try语句中,执行完后会自动关闭。
        {
            // ResultSet有系列的getXxx(列索引 | 列名),用于获取记录指针
            // 指向行、特定列的值,不断地使用next()将记录指针下移一行,
            // 如果移动之后记录指针依然指向有效行,则next()方法返回true。
            while(rs.next())
            {
                System.out.println(rs.getInt(1) + "	"
                    + rs.getString(2) + "	"
                    + rs.getString(3) + "	"
                    + rs.getString(4));
            }
        }
    }
}
View Code

 执行DDL语句的例子:

import java.util.*;
import java.io.*;
import java.sql.*;

public class ExecuteDDL
{
    private String driver;
    private String url;
    private String user;
    private String pass;
    public void initParam(String paramFile)
        throws Exception
    {
        // 使用Properties类来加载属性文件
        Properties props = new Properties();
        props.load(new FileInputStream(paramFile));
        driver = props.getProperty("driver");
        url = props.getProperty("url");
        user = props.getProperty("user");
        pass = props.getProperty("pass");
    }
    public void createTable(String sql)throws Exception //注意这个返回值类型
    {
        // 加载驱动
        Class.forName(driver);
        try(
        // 获取数据库连接
        Connection conn = DriverManager.getConnection(url , user , pass);
        // 使用Connection来创建一个Statment对象
        Statement stmt = conn.createStatement())
        {
            // 执行DDL,创建数据表
            stmt.executeUpdate(sql);
        }
    }
    public static void main(String[] args) throws Exception
    {
        ExecuteDDL ed = new ExecuteDDL();
        ed.initParam("mysql.ini");
        ed.createTable("create table jdbc_test "
            + "( jdbc_id int auto_increment primary key, "
            + "jdbc_name varchar(255), "
            + "jdbc_desc text);");
        System.out.println("-----建表成功-----");
    }
}
View Code

执行DML语句的例子 :

import java.util.*;
import java.io.*;
import java.sql.*;

public class ExecuteDML
{
    private String driver;
    private String url;
    private String user;
    private String pass;

    public void initParam(String paramFile)
        throws Exception
    {
        // 使用Properties类来加载属性文件
        Properties props = new Properties();
        props.load(new FileInputStream(paramFile));
        driver = props.getProperty("driver");
        url = props.getProperty("url");
        user = props.getProperty("user");
        pass = props.getProperty("pass");
    }
    public int insertData(String sql)throws Exception//注意这里的返回值类型
    {
        // 加载驱动
        Class.forName(driver);
        try(
            // 获取数据库连接
            Connection conn = DriverManager.getConnection(url
                , user , pass);
            // 使用Connection来创建一个Statment对象
            Statement stmt = conn.createStatement())
        {
            // 执行DML,返回受影响的记录条数
            return stmt.executeUpdate(sql);
        }
    }
    public static void main(String[] args)throws Exception
    {
        ExecuteDML ed = new ExecuteDML();
        ed.initParam("mysql.ini");
        int result = ed.insertData("insert into jdbc_test(jdbc_name,jdbc_desc)"
            + "select s.student_name , t.teacher_name "
            + "from student_table s , teacher_table t "
            + "where s.java_teacher = t.teacher_id;");
        System.out.println("--系统中共有" + result + "条记录受影响--");
    }
}
View Code

 当不清楚SQL语句类型时的例子:

import java.util.*;
import java.io.*;
import java.sql.*;

public class ExecuteSQL
{
    private String driver;
    private String url;
    private String user;
    private String pass;
    public void initParam(String paramFile)throws Exception
    {
        // 使用Properties类来加载属性文件
        Properties props = new Properties();
        props.load(new FileInputStream(paramFile));
        driver = props.getProperty("driver");
        url = props.getProperty("url");
        user = props.getProperty("user");
        pass = props.getProperty("pass");
    }
    public void executeSql(String sql)throws Exception
    {
        // 加载驱动
        Class.forName(driver);
        try(
            // 获取数据库连接
            Connection conn = DriverManager.getConnection(url
                , user , pass);
            // 使用Connection来创建一个Statement对象
            Statement stmt = conn.createStatement())
        {
            // 执行SQL,返回boolean值表示是否包含ResultSet
            boolean hasResultSet = stmt.execute(sql);
            // 如果执行后有ResultSet结果集
            if (hasResultSet)
            {
                try(
                    // 获取结果集
                    ResultSet rs = stmt.getResultSet())
                {
                    // ResultSetMetaData是用于分析结果集的元数据接口
                    ResultSetMetaData rsmd = rs.getMetaData();
                    int columnCount = rsmd.getColumnCount();
                    // 迭代输出ResultSet对象
                    while (rs.next())
                    {
                        // 依次输出每列的值
                        for (int i = 0 ; i < columnCount ; i++ )
                        {
                            System.out.print(rs.getString(i + 1) + "	");
                        }
                        System.out.print("
");
                    }
                }
            }
            else
            {
                System.out.println("该SQL语句影响的记录有"
                    + stmt.getUpdateCount() + "条");
            }
        }
    }
    public static void main(String[] args) throws Exception
    {
        ExecuteSQL es = new ExecuteSQL();
        es.initParam("mysql.ini");
        System.out.println("------执行删除表的DDL语句-----");
        es.executeSql("drop table if exists my_test");
        System.out.println("------执行建表的DDL语句-----");
        es.executeSql("create table my_test"
            + "(test_id int auto_increment primary key, "
            + "test_name varchar(255))");
        System.out.println("------执行插入数据的DML语句-----");
        es.executeSql("insert into my_test(test_name) "
            + "select student_name from student_table");
        System.out.println("------执行查询数据的查询语句-----");
        es.executeSql("select * from my_test");
    }
}
View Code

使用PreparedStatement执行SQL语句的例子(使用这种方法,可以防止SQL注入,比如在登录框中输入‘or true or’)

import java.util.*;
import java.io.*;
import java.sql.*;

public class PreparedStatementTest
{
    private String driver;
    private String url;
    private String user;
    private String pass;
    public void initParam(String paramFile)throws Exception
    {
        // 使用Properties类来加载属性文件
        Properties props = new Properties();
        props.load(new FileInputStream(paramFile));
        driver = props.getProperty("driver");
        url = props.getProperty("url");
        user = props.getProperty("user");
        pass = props.getProperty("pass");
        // 加载驱动
        Class.forName(driver);
    }
    public void insertUseStatement()throws Exception
    {
        long start = System.currentTimeMillis();
        try(
            // 获取数据库连接
            Connection conn = DriverManager.getConnection(url
                , user , pass);
            // 使用Connection来创建一个Statment对象
            Statement stmt = conn.createStatement())
        {
            // 需要使用100条SQL语句来插入100条记录
            for (int i = 0; i < 100 ; i++ )
            {
                stmt.executeUpdate("insert into student_table values("
                    + " null ,'姓名" + i + "' , 1)");
            }
            System.out.println("使用Statement费时:"
                + (System.currentTimeMillis() - start));
        }
    }
    public void insertUsePrepare()throws Exception
    {
        long start = System.currentTimeMillis();
        try(
            // 获取数据库连接
            Connection conn = DriverManager.getConnection(url
                , user , pass);
            // 使用Connection来创建一个PreparedStatement对象
            PreparedStatement pstmt = conn.prepareStatement(
                "insert into student_table values(null,?,1)"))

        {
            // 100次为PreparedStatement的参数设值,就可以插入100条记录
            for (int i = 0; i < 100 ; i++ )
            {
                pstmt.setString(1 , "姓名" + i);
                pstmt.executeUpdate();
            }
            System.out.println("使用PreparedStatement费时:"
                + (System.currentTimeMillis() - start));
        }
    }
    public static void main(String[] args) throws Exception
    {
        PreparedStatementTest pt = new PreparedStatementTest();
        pt.initParam("mysql.ini");
        pt.insertUseStatement();
        pt.insertUsePrepare();
    }
}
View Code

使用CallableStatement调用存储过程的例子

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.io.*;
import java.sql.*;

public class CallableStatementTest
{
    private String driver;
    private String url;
    private String user;
    private String pass;
    public void initParam(String paramFile)throws Exception
    {
        // 使用Properties类来加载属性文件
        Properties props = new Properties();
        props.load(new FileInputStream(paramFile));
        driver = props.getProperty("driver");
        url = props.getProperty("url");
        user = props.getProperty("user");
        pass = props.getProperty("pass");
    }
    public void callProcedure()throws Exception
    {
        // 加载驱动
        Class.forName(driver);
        try(
            // 获取数据库连接
            Connection conn = DriverManager.getConnection(url
                , user , pass);
            // 使用Connection来创建一个CallableStatment对象
            CallableStatement cstmt = conn.prepareCall(
                "{call add_pro(?,?,?)}"))
        {
            cstmt.setInt(1, 4);
            cstmt.setInt(2, 5);
            // 注册CallableStatement的第三个参数是int类型
            cstmt.registerOutParameter(3, Types.INTEGER);
            // 执行存储过程
            cstmt.execute();
            // 获取,并输出存储过程传出参数的值。
            System.out.println("执行结果是: " + cstmt.getInt(3));
        }
    }
    public static void main(String[] args) throws Exception
    {
        CallableStatementTest ct = new CallableStatementTest();
        ct.initParam("mysql.ini");
        ct.callProcedure();
    }
}
View Code

管理结果集:


可滚动、可更新的结果集

需要在创建Statement或者PrepareStatement时传入额外的参数,如下面例子:

import java.util.*;
import java.io.*;
import java.sql.*;

public class ResultSetTest
{
    private String driver;
    private String url;
    private String user;
    private String pass;
    public void initParam(String paramFile)throws Exception
    {
        // 使用Properties类来加载属性文件
        Properties props = new Properties();
        props.load(new FileInputStream(paramFile));
        driver = props.getProperty("driver");
        url = props.getProperty("url");
        user = props.getProperty("user");
        pass = props.getProperty("pass");
    }
    public void query(String sql)throws Exception
    {
        // 加载驱动
        Class.forName(driver);
        try(
            // 获取数据库连接
            Connection conn = DriverManager.getConnection(url , user , pass);
            // 使用Connection来创建一个PreparedStatement对象
            // 传入控制结果集可滚动,可更新的参数。
            PreparedStatement pstmt = conn.prepareStatement(sql
                , ResultSet.TYPE_SCROLL_INSENSITIVE
                , ResultSet.CONCUR_UPDATABLE);
            ResultSet rs = pstmt.executeQuery())
        {
            rs.last();
            int rowCount = rs.getRow();
            for (int i = rowCount; i > 0 ; i-- )
            {
                rs.absolute(i);
                System.out.println(rs.getString(1) + "	"
                    + rs.getString(2) + "	" + rs.getString(3));
                // 修改记录指针所有记录、第2列的值
                rs.updateString(2 , "学生名" + i);
                // 提交修改
                rs.updateRow();
            }
        }
    }
    public static void main(String[] args) throws Exception
    {
        ResultSetTest rt = new ResultSetTest();
        rt.initParam("mysql.ini");
        rt.query("select * from student_table");
    }
}
View Code


处理Blob类型数据

Blob(Binary Long object)是二进制长对象的意思。使用该类可以吧图片、声音等文件的二进制数据保存在数据库中,并可以从数据库中恢复指定文件。

通过PrepareStatement的setBinaryStream(int parameterIndex,InputStream x),该方法可以指定参数传入二进制流。

如果需要从ResultSet中取出Blob数据,可以调用ResultSet的getBlob(int columnIndex)来返回一个Blob对象,然后再通过Blob对象的getBinaryStream()方法获取该Blob数据的输入流,也可以使用Blob对象的getBytes()方法直接读取该Blob对象封装的二进制数据。

使用ResultSetMetaData分析结果集:

该对象可以通过ResultSet的getMetaData()方法来放回。常用的方法有:

  • int getColumnCount():返回该ResultSet的列数量
  • String getColumnName(int column):返回指定索引的列名
  • int getColumnType(int column):返回指定索引的列类型

事务处理

 事务是由一步或几步数据库操作序列组成的逻辑执行单元,这系列操作要么全部执行,要么全部放弃执行。

事务有四个特性:原子性、一致性、隔离性、持续性。

数据库事务由下列语句组成。

一组DML语句,一条DDL语句,一条DCL语句。DDL和DCL语句最多只能有一条,因为DDL和DCL语句都会导致事务立即提交。

事务提交方式(没有提交前事务中的语句不会生效)

1.显式提交:使用commit

2.自动提交:执行DDL或DCL语句,或者程序正常退出。

事务回滚方式:(没有生效的事务可以回滚)

1.显式回滚:使用rollback

2.自动回滚:系统错误或者强行退出

自动提交和开始事务是对立的,开始事务功能后,就会将自动提交的功能关闭。正常情况下需要手动关闭自动提交。

JDBC对事务的支持

可以调用Connection的setAutoCommit()方法来关闭自动提交,开启事务。getAutoCommit()返回自动提交模式。commit()提交事务。rollback()回滚事务。

例子:

import java.sql.*;
import java.io.*;
import java.util.*;

public class TransactionTest
{
    private String driver;
    private String url;
    private String user;
    private String pass;
    public void initParam(String paramFile)throws Exception
    {
        // 使用Properties类来加载属性文件
        Properties props = new Properties();
        props.load(new FileInputStream(paramFile));
        driver = props.getProperty("driver");
        url = props.getProperty("url");
        user = props.getProperty("user");
        pass = props.getProperty("pass");
    }
    public void insertInTransaction(String[] sqls) throws Exception
    {
        // 加载驱动
        Class.forName(driver);
        try(
            Connection conn = DriverManager.getConnection(url , user , pass))
        {
            // 关闭自动提交,开启事务
            conn.setAutoCommit(false);
            try(
                // 使用Connection来创建一个Statment对象
                Statement stmt = conn.createStatement())
            {
                // 循环多次执行SQL语句
                for (String sql : sqls)
                {
                    stmt.executeUpdate(sql);
                }
            }
            // 提交事务
            conn.commit();
        }
    }
    public static void main(String[] args) throws Exception
    {
        TransactionTest tt = new TransactionTest();
        tt.initParam("mysql.ini");
        String[] sqls = new String[]{
            "insert into student_table values(null , 'aaa' ,1)",
            "insert into student_table values(null , 'bbb' ,1)",
            "insert into student_table values(null , 'ccc' ,1)",
            // 下面这条SQL语句将会违反外键约束,
            // 因为teacher_table中没有ID为5的记录。
            "insert into student_table values(null , 'ccc' ,5)" //
        };
        tt.insertInTransaction(sqls);
    }
}
View Code

使用DatabaseMetaData分析数据库信息

通过Connection提供的getMetaData()方法获取DatabaseMetaData对象。许多DatabaseMetaData方法是以ResultSet对象的形式返回查询信息,然后使用ResultSet中的常规方法获取内容。如果没有内容就返回一个空的ResultSet对象。

DatabaseMetaData的许多方法都需要传入一个xxxPattern模式字符串,这里的xxxPattern不是正则表达式,而是SQL里的模式字符串。

即用百分号(%)代表任意多个字符,使用下划线(_)代表一个字符。通常情况下,如果把该模式字符串的参数值设置为null,即表明该参数不过为过滤条件。

例子:

import java.sql.*;
import java.util.*;
import java.io.*;

public class DatabaseMetaDataTest
{
    private String driver;
    private String url;
    private String user;
    private String pass;
    public void initParam(String paramFile)throws Exception
    {
        // 使用Properties类来加载属性文件
        Properties props = new Properties();
        props.load(new FileInputStream(paramFile));
        driver = props.getProperty("driver");
        url = props.getProperty("url");
        user = props.getProperty("user");
        pass = props.getProperty("pass");
    }
    public void info() throws Exception
    {
        // 加载驱动
        Class.forName(driver);
        try(
            // 获取数据库连接
            Connection conn = DriverManager.getConnection(url
                , user , pass))
        {
            // 获取的DatabaseMetaData对象
            DatabaseMetaData dbmd = conn.getMetaData();
            // 获取MySQL支持的所有表类型
            ResultSet rs = dbmd.getTableTypes();
            System.out.println("--MySQL支持的表类型信息--");
            printResultSet(rs);
            // 获取当前数据库的全部数据表
            rs = dbmd.getTables(null,null, "%" , new String[]{"TABLE"});
            System.out.println("--当前数据库里的数据表信息--");
            printResultSet(rs);
            // 获取student_table表的主键
            rs = dbmd.getPrimaryKeys(null , null, "student_table");
            System.out.println("--student_table表的主键信息--");
            printResultSet(rs);
            // 获取当前数据库的全部存储过程
            rs = dbmd.getProcedures(null , null, "%");
            System.out.println("--当前数据库里的存储过程信息--");
            printResultSet(rs);
            // 获取teacher_table表和student_table之间的外键约束
            rs = dbmd.getCrossReference(null,null, "teacher_table"
                , null, null, "student_table");
            System.out.println("--teacher_table表和student_table之间"
                + "的外键约束--");
            printResultSet(rs);
            // 获取student_table表的全部数据列
            rs = dbmd.getColumns(null, null, "student_table", "%");
            System.out.println("--student_table表的全部数据列--");
            printResultSet(rs);
        }
    }
    public void printResultSet(ResultSet rs)throws SQLException
    {
        ResultSetMetaData rsmd = rs.getMetaData();
        // 打印ResultSet的所有列标题
        for (int i = 0 ; i < rsmd.getColumnCount() ; i++ )
        {
            System.out.print(rsmd.getColumnName(i + 1) + "	");
        }
        System.out.print("
");
        // 打印ResultSet里的全部数据
        while (rs.next())
        {
            for (int i = 0; i < rsmd.getColumnCount() ; i++ )
            {
                System.out.print(rs.getString(i + 1) + "	");
            }
            System.out.print("
");
        }
        rs.close();
    }
    public static void main(String[] args)
        throws Exception
    {
        DatabaseMetaDataTest dt = new DatabaseMetaDataTest();
        dt.initParam("mysql.ini");
        dt.info();
    }
}
View Code
原文地址:https://www.cnblogs.com/moonpool/p/5559294.html