小透明的java学习记录(2)——数据库编程(一)

本文都是以MySQL为例,因为学习的时候只下载了MySQL数据库。
根据《Java 核心技术 卷2 高级特效》的顺序来学习,本文的很多实例也都是从书中直接搬过来的。

JDBC介绍

JDBC(Java DataBase Connectivity):java数据库连接。

JDBC是一套单纯的Java API,不同的数据库提供自己独有的驱动程序,将其插入到驱动管理器中。所有通过这个API编写的程序都可以与驱动管理器进行通信。这就意味着,如果程序员想要使用数据库,就不得不使用JDBC API。

数据库的简单介绍

可以将数据库想象成多个行列表格组成的表集,可以具象为如下表格

表1 Author表
Author_IDNameFname
ALEXAlexanderCristopher
BROOBrooksFrederick P.
表2 Books表
TitleISBNPublisher_IDPrice
A Guide to the SQL Standard0-201-96426020147.95
APattern Language: Towns,Buildings, Construction0-19-501919-901965.00
表3 BooksAuthors表
ISBNAuthor_IDSeq_No
0-201-96426-0DATE1
0-201-96426DARW2
0-19-501919-9ALEX1
表4 Publishers表
Publisher_IDNameURL
0201Addison-Wesleywww.aw-bc.com
0407John Wiley & Sonswww.wiley.com

可以通过工具查看数据库中的数据,在没有安装工具的情况下可以通过cmd执行SQL语句查看数据库中的数据。按照惯例,SQL关键字全部使用大写字母,当然也可以不这么做。

1.查询Books表格中的数据,*代指所有的意思,查询语句中FROM是必不可少的,它指定查找源

SELECT * FROM Books

2.查询Books表格中的具体数据

SELECT ISBN, Price, Title FROM Books

3.还可以在查询语句中使用WHERE语句定义想要查找的对象需要满足的条件,需要注意的一点是,SQL使用 = 和 <> 表示等于和不等于,而非 == 和 !=

SELECT Title, ISBN, Price FROM Books WHERE Price <> 65.00

4.WHERE语句也可以用LIKE操作来实现模式匹配,但这里的通配符不是通常使用的‘*’和‘?’,而是用‘%’表示多个或单个字符,用‘_’表示单个字符,以下这条语句排除了Title里带‘linux’和‘unix’的图书

SELECT Title, ISBN, Price FROM Books WHERE Title Not LIKE '%n_x%'

返回所有带单引号的书名,字符串中的单引号需要用2个单引号表示

SELECT Title FROM Books WHERE Title LIKE '%''%'

只找出那些图书与出版社相匹配的数据

SELECT Title FROM Books WHERE Books.Publisher_Id = Publishers.Publisher_Id

也可以使用SQL来改变数据库中的数据EE

1.将书名中包含“C++”的图书降价5美元

UPDATE Books SET Price = Price - 5.00 WHERE Title LIKE '%C++%'

2.删除所有C++图书

DELETE FROM Books WHERE Title LIKE '%C++%'

3.在表中插入数据

INSERT INTO Books VALUES ('A Guide to the SQL Standard', '0-201-96426-0', '0201', '47.95')

4.当然,在增删改查之前,我们需要创建表

CREATE TABLE Books
(
Title CHAR(60),
ISBN CHAR(13),
Publisher_Id CHAR(6),
Price DECIMAL(10, 2)
)
表5 SQL数据类型
数据类型说明
CHARACTER(N)或CHAR(n)固定长度的字符串
NUMERIC(m, n), DECIMAL(m, n) or DEC(m, n)m位长度的十进制数,其中小数点后位n位

JDBC配置

1.安装MYSQL数据库
官网(https://dev.mysql.com/downloads/)
下载免安装版,直接解压,将bin目录加到系统路径下;
可以解压在D:\mysql-8.0.16-winx64
添加系统路径D:\mysql-8.0.16-winx64\bin
在D:\mysql-8.0.16-winx64中新建my.ini

[mysql]
     default-character-set=utf8
     [mysqld]
     port=3306
     basedir=D:\mysql-8.0.16-winx64
     datadir=D:\mysql-8.0.16-winx64\data
     max_connections=200
     character-set-server=utf8
     default-storage-engine=INNODB

在bin路径下打开cmd输入命令 mysqld --initialize-insecure ,可以发现自动创建了一个data文件夹
继续输入命令 mysqld -install 安装数据库
继续输入命令 net start server 启动数据库
输入命令 mysql -u root -p 登陆;
输入命令CREATE DATABASE wangxianlu;创建名为wangxianlu的数据库;

2.数据库URL
在连接数据库之前,必须弄清楚各种与数据库类型相关的参数,例如主机名、端口号和数据库名。
JDBC使用了一种与普通URL类似的语法来描述数据源,以下是2个实例

jdbc:mysql://localhost:3306/wangxianlu;create=true
jdbc:mysql:wangxianlu

3.驱动程序jar文件
下载mysql-connector-java-5.1.44-bin.jar包
把该jar包放在工程的lib目录下
添加到程序的libraries里

4.连接数据库
可以在java代码中打开一个数据库并操作它

//建立一个指定数据库的连接,并返回一个Connection对象
static Connectin getConnection(String url, String user, String password)

具体请参见如下代码及注释。

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

public class TestDB {
    //数据库url
    static String url = "jdbc:mysql://localhost:3306/wangxianlu?useSSL=false";
    //用户名
    static String username = "root";
    //密码
    static String password = "root";

    public static void main(String[] args) throws IOException {
        try{
            runTest();
        }catch(SQLException e){
            for(Throwable t : e){
                t.printStackTrace();
            }
        }
    }

    public static void runTest() throws SQLException, IOException{
        try(
             //连接数据库
             Connection conn = DriverManager.getConnection(url, username, password);
             Statement stat = conn.createStatement();){
            stat.executeUpdate("CREATE TABLE Greetings (Message CHAR(20))");
            stat.executeUpdate("INSERT INTO Greetings values ('Hello, World!')");
            try(ResultSet result = stat.executeQuery("SELECT * FROM Greetings")){
                if(result.next()){
                    System.out.println(result.getString(1));
                }
                stat.executeUpdate("DROP TABLE Greetings");
            }
        }
    }
}

使用JDBC语句

在执行SQL语句之前,首先需要创建一个Statement对象,要创建Statement对象,首先要调用DriverManager.getConnection方法与数据库进行连接

Connection conn = DriverManeger.getConection(url, username, password);
Statement stat = conn.createStatement();

接着,把要执行的SQL语句放入到字符串中,例如:

String command = "UPDATE Books SET Price = Price - 5.00 WHERE Title NOT LIKE '%Introduction%'";

然后,使用Statement接口中的executeUpdate方法:

stat.executeUpdate(command);

executeUpdate方法返回受SQL语句影响的行数,对于不返回行数的语句返回0。

executeUpdate方法可以用在诸如DELETE,INSERT,UPDATE之类的操作,也可以执行诸如 CREATE TABLE 和 DROP TABLE 之类的数据定义语句。但是,执行查询语句时,必须使用executeQuery方法。

另外还有一个execute方法可以执行任意的SQL语句,此方法通常只用于由用户提交的交互式查询。我的理解是最好是不使用用execute方法,除非是在不确定执行操作的时候才用execute方法(例如直接让用户输入命令)。

当我们执行查询语句时,最关心的是查询结果,executeQuery方法会返回一个ResultSet类型的对象,可以通过它每次一行的迭代遍历所有查询结果

ResultSet rs = stat.executeQuery("SELECT * FROM Books");
        while(rs.next()){
            //look at a row of the result set
        }

以下列举了Connection, Statement,和ResultSet中的方法
java.sql.Connection

//创建一个Statement对象,可以执行不带参数的SQL查询和更新
Statement createStatement()
//立即关闭当前连接,并释放由它创建的JDBC资源
void close

java.sql.Statement

//执行给定字符串中的SQL语句,并返回一个用于查看查询结果的resultSet对象
ResultSet executeQuery(String sqlQuery)
//执行给定字符串中的SQL语句,并返回受影响的行数
int executeUpdate(String sqlStatement);
//执行字符串中给定的INSERT,UPDATE,DELETE语句,还可以执行数据定义语言(DDL)的语句,如CREATE TABLE,返回受影响的行数,如果是没有更新计数的语句,则返回0
int executeLargeUpdate(String sqlStatement);
//执行给定字符串中的SQL语句,可能会产生多个结果集和更新计数,如果第一个执行结果是结果集,则返回true,反之返回false。调用getResultSet或getUpdateCount方法可以得到第一个执行结果
boolean execute(String sqlStatement)
//返回前一条查询语句的结果集,如果前一条语句未产生结果集,则返回null,对于每一条执行过的语句,该方法只能被调用一次
ResultSet getResultSet()
//返回前一条执行语句的受影响行数
int getUpdateCount()
//返回前一条执行语句的受影响行数,如果前一条语句未产生结果集,则返回-1,对于每一条执行过的语句,该方法只能被调用一次
long getLargeUpdateCount()
//关闭Statement对象以及它所对应的结果集
void close()
//语句如果被关闭则返回true
boolean isClosed()
//使得一旦所有的语句被关闭,则关闭该语句
void closeOnCompletion()

java.sql.ResultSet

//将结果集中的当前行向前移动一行。如果已经到达最后一行的后面,则返回false。注意:初始情况下必须调用该方法才能转到第一行
boolean next()
//Xxx指数据类型,如int, double String Date
Xxx getXxx(int columnNumber)
//Xxx指数据类型,如int, double String Date
Xxx getXxx(String columnLabel)
//对于给定的列序号或列标签返回或更新该列的值,并将值转换为指定的类型
<T> T getObject(int columnIndex, Object x, SQLType targetSqlType)
<T> T getObject(String columnLabel, Object x, SQLType targetSqlType)
//用给定的列名,返回该列的序号
int findColumn(String columnName)
//关闭当前结果集
void cloce()
//如果该语句被关闭,则返回true
boolean isClosed()

使用完ResultSet,Statement或Connection对象时,应立即调用close()方法。这些对象都使用了规模较大的数据结构,它们会占用数据库存服务器上的有限资源。

组装数据库

import java.io.IOException;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import java.util.Scanner;

public class TestDB {

    static String url = "jdbc:mysql://localhost:3306/wangxianlu?useSSL=false";
    static String username = "root";
    static String password = "root";

    public static void main(String[] args) throws IOException{

        try(Scanner in = args.length == 0 ? new Scanner(System.in) :
                new Scanner(Paths.get(args[0]), "utf-8")){
            try(Connection conn = DriverManager.getConnection(url, username, password);
                Statement stat = conn.createStatement();){
                while(true){
                    if(args.length == 0){
                        System.out.println("ENTER COMMAND OR EXIT TO EXIT: ");
                    }
                    if(!in.hasNextLine())return;
                    String line = in.nextLine().trim();
                    if(line.equalsIgnoreCase("EXIT"))return;
                    if(line.endsWith(";")){
                        line = line.substring(0, line.length() - 1);
                    }
                    try{
                        boolean isResult = stat.execute(line);
                        if(isResult){
                            try(ResultSet rs = stat.getResultSet()){
                                showResultSet(rs);
                            }
                        }else{
                            int updateCount = stat.getUpdateCount();
                            System.out.println(updateCount + "rows updated");
                        }
                    }catch(SQLException ex){
                        for(Throwable e : ex){
                            e.printStackTrace();
                        }
                    }
                }
            }catch (SQLException ex){
                for(Throwable t : ex){
                    t.printStackTrace();
                }
            }
        }
    }

    public static Connection getConnection() throws SQLException, IOException{
        Properties props = new Properties();
        return DriverManager.getConnection(url, username, password);
    }

    public static void showResultSet(ResultSet result) throws SQLException{
        ResultSetMetaData metaData = result.getMetaData();
        int columnCount = metaData.getColumnCount();
        for(int i = 1; i <= columnCount; i++){
            if(i > 1) System.out.print(", ");
            System.out.print(metaData.getColumnLabel(i));
        }
        System.out.println();

        while (result.next()){
            for(int i = 1; i <= columnCount; i++){
                if(i > 1) System.out.print(", ");
                System.out.print(result.getString(i));
            }
            System.out.println();
        }
    }
}

将下列语句一句一句执行就可以了>_<

CREATE TABLE Author (Author_ID CHAR(6), Name CHAR(30), Fname CHAR(30));
CREATE TABLE Books (Title CHAR(100), ISBN CHAR(30), Publisher_ID CHAR(6), Price DECIMAL(10, 2));
CREATE TABLE BooksAuthors (ISBN CHAR(30), Author_ID CHAR(30), Seq_No CHAR(6));
CREATE TABLE Publishers (Publisher_ID CHAR(6), Name CHAR(30), URL CHAR(80));
INSERT INTO Author VALUES ('ALEX', 'Alexander', 'Cristopher');
INSERT INTO Author VALUES ('BROO', 'Brooks', 'Frederick P.');
INSERT INTO Books VALUES ('A Guide to the SQL Standard', '0-201-96426', '0201', '47.95');
INSERT INTO Books VALUES ('APattern Language: Towns,Buildings, Construction', '0-19-501919-9', '019', '65.00');
INSERT INTO BooksAuthors VALUES ('0-201-96426-0', 'DATE', '1');
INSERT INTO BooksAuthors VALUES ('0-201-96426', 'DARW', '2');
INSERT INTO BooksAuthors VALUES ('0-19-501919-9', 'ALEX', '1');
INSERT INTO Publishers VALUES ('0201', 'Addison-Wesley', 'www.aw-bc.com');
INSERT INTO Publishers VALUES ('0407', 'John Wiley & Sons', 'www.wiley.com');

执行查询操作

除了上面提到的查询方法,在此基础上,如果存在多个不确定的查询目标,例如用户想要查询Publisher_Id为自己输入的值,此时可以使用预备语句(prepared statement)
在预备查询语句中,每个宿主变量都用’?'代替,下面我们定义一个查询语句

        //定义SQL语句
        String publisherQuery = "SELECT Books.Price, Books.Title" +
                " FROM Books, Publishers" +
                " WHERE Books.Publisher_Id" +
                " = Publishers.Publisher_Id AND Publishers.Name = ?";
        //创建预备语句
        PreparedStatement stat = conn.prepareStatement(publisherQuery);

此时可以使用set方法将’?‘变量绑到实际的值上,1表示第一个’?’,如果有多个‘?’,可以依序使用setXxx方法赋值。如果想要重用预备查询语句,除非使用set方法重新赋值,或者是使用clearParameters方法,否则所有变量的绑定都不会改变。

        stat.setString(1, "Addison-Wesley");

在所有变量都绑定了具体的值以后,就可以执行查询操作了

        ResultSet rs = stat.executeQuery();

如果UPDATE语句需要使用出版社代码,而我们只知道出版社名称,则可以使用嵌套语句来解决

    String command = "UPDATE Books SET Price =" +
            "Price + ? WHERE Books.Publisher_Id =" +
            " (SELECT Publisher_Id FROM Publishers WHERE Name = ?)";

以下为完整代码

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class QueryTest {
    private static final String url = "jdbc:mysql://localhost:3306/wangxianlu?useSSL=false";
    private static final String username = "root";
    private static final String password = "root";

    private static final String allQuery = "SELECT Books.Price, Books.Title" +
            " FROM Books";
    private static final String authorpublisherQuery = "SELECT Books.Price, " +
            "Books.Title FROM Books, Author, BooksAuthors, Publishers" +
            " WHERE Author.Author_Id = BooksAuthor.Author_Id" +
            " AND BooksAuthors.ISBN = Books.ISBN" +
            " Books.Publisher_Id = Publishers.Publisher_Id" +
            " AND Authors.Name = ?" +
            " AND Publisher.Name = ?";
    private static final String authorQuery = "SELECT Books.Price, Books.Title" +
            "FROM Books, Author, BooksAuthors" +
            " WHERE Author.Author_Id = BooksAuthor.Author_Id" +
            " AND BooksAuthors.ISBN = Books.ISBN" +
            " AND Authors.Name = ?";
    private static final String publisherQuery = "SELECT Books.Price, Books.Title" +
            " FROM Books, Publishers" +
            " WHERE Books.Publisher_Id = Publishers.Publisher_Id" +
            " AND Publisher.Name = ?";
    private static final String priceUpdate = "UPDATE Books SET Price = Price + ?" +
            "WHERE Books.Publisher_Id = (SELECT Publisher_Id FROM Publishers WHERE Name = ?)";

    private static Scanner in;
    private static ArrayList<String> authors = new ArrayList<>();
    private static ArrayList<String> publishers = new ArrayList<>();


    public static void main(String[] args) throws SQLException {

        //连接数据库
        try (Connection conn = DriverManager.getConnection(url, username, password)) {
            //赋值给用户输入in
            in = new Scanner(System.in);
            //赋初始值
            authors.add("Any");
            publishers.add("Any");
            //创建Statement对象
            try (Statement stat = conn.createStatement()) {
                String query = "SELECT Name FROM Author";
                //遍历Author表
                try (ResultSet rs = stat.executeQuery(query)) {
                    while (rs.next()) {
                        //Author表内的值赋给authors
                        authors.add(rs.getString(1));
                    }
                }
                query = "SELECT Name FROM Publishers";
                //遍历Publishers表
                try (ResultSet rs = stat.executeQuery(query)) {
                    while (rs.next()) {
                        //Publishers表内的值赋给publishers
                        publishers.add(rs.getString(1));
                    }
                }
            }
            boolean done = false;
            while(! done){
                //提示用户输入q,c,或e
                System.out.print("Q)uery  C)hange prices  E)xit: ");
                String input = in.next().toUpperCase();
                //用户输入q,则执行查询函数
                if(input.equals("Q")) executeQuery(conn);
                //用户输入c,则执行更新函数
                if(input.equals("C")) changePrices(conn);
                //用户输入其他,则程序执行完毕
                else done = true;
            }
        }
    }
    //查询函数
    private static void executeQuery(Connection conn) throws SQLException{
        //选择函数,获取用户二次输入
        String author = select("Authors: ", authors);
        String publisher = select("Publishers: ",  publishers);
        PreparedStatement stat;
        if(! author.equals("Any") && publisher.equals("Any")) {
            stat = conn.prepareStatement(authorpublisherQuery);
            stat.setString(1, author);
            stat.setString(2, publisher);
        }else if (!author.equals("Any") && publisher.equals("Any")){
            stat = conn.prepareStatement(authorQuery);
            stat.setString(1, author);
        }else if (author.equals("Any") && !publisher.equals("Any")){
            stat = conn.prepareStatement(publisherQuery);
            stat.setString(1, publisher);
        }else stat = conn.prepareStatement(allQuery);

        try(ResultSet rs = stat.executeQuery()){
            while (rs.next()) {
                System.out.println(rs.getString(1) + ", " + rs.getString(2));
            }
        }
    }
    //更新函数
    private static void changePrices(Connection conn) throws SQLException{
        //选择函数,获取用户二次输入
        String publisher = select("Publishers: ", publishers.subList(1, publishers.size()));
        System.out.print("Change prices by: ");
        //获取用户第三次输入,获取用户想要涨价的值
        double priceChange = in.nextDouble();
        PreparedStatement stat = conn.prepareStatement(priceUpdate);
        stat.setDouble(1, priceChange);
        stat.setString(2, publisher);
        int r = stat.executeUpdate();
        System.out.println(r + "records updated.");
    }
    //选择函数
    public static String select(String prompt, List<String> options) {
        while (true) {
            //提示用户输入哪个表的信息
            System.out.println("请选择要查询信息的数字代号");
            System.out.println(prompt);
            for(int i = 0; i < options.size(); i++)
                System.out.printf("%2d) %s%n", i + 1, options.get(i));
                //获取用户需要的表信息
                int sel = in.nextInt();
                if(sel > 0 && sel <= options.size())
                    return options.get(sel - 1);
        }
    }
}

执行结果
在这里插入图片描述
这个实在是太多了,分2节写吧>_<

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值