JDBC:もう一度あなたを愛するようにそれを取ります
(A)JDBCエントリー
(1)概要
Javaデータベース・コネクティビティ(Javaデータベース接続、JDBCと呼ばれる)は、Java言語を標準化するために使用されるクライアントのどのプログラム、データベース・アクセス、データベース内の照会及び更新データ等の方法を提供するアプリケーションプログラムインタフェースを。JDBCはまた、Sun Microsystems、Inc.の商標です。JDBCをされ、リレーショナル指向のデータベースを。
簡単な説明: Java言語によるSQL文の実装なので、データベースの操作
(2)理由
異なるデータベースでJavaオペレーションをしたい、データベースは、特定のAPIに依存し実行する必要があり、アイデアを簡単にするために、Sunはそれが唯一のインターフェースを提供し、JDBCあるすべてのAPIのためのリレーショナルデータベースのセットを定義しています、達成するために、データベース・ベンダーの具体的な実現に行き、そして私たちは、開発者として、我々はデータベースに対して動作し、あなただけのJDBCベースに必要
(B)JDBCを使用するのは簡単
私たちは、単にデータベース内のデータを照会するためにJDBCを使用し、コンソールに出力
簡単なデモのために、我々は非常に単純なテーブルを作成します
CREATE TABLE student(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
score DOUBLE(4,1)
);
INSERT student(id,NAME,score) VALUES (1,'张三',98);
INSERT student(id,NAME,score) VALUES (2,'李四',96);
INSERT student(id,NAME,score) VALUES (3,'王五',100);
私たちは、生徒のカテゴリ内の情報に基づいて対応するデータベースを書きました
public class Student {
private int id;
private String name;
private double score;
//省略构造、Get、Set、toString方法
......
}
ここではJDBCクエリ機能の簡単な使用であります
package cn.ideal.jdbc;
import cn.ideal.domain.Student;
import java.sql.*;
public class JdbcDemo {
public static void main(String[] args) {
//导入数据库驱动包
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
//获取与数据库的连接对象
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "root99");
//定义sql语句
String sql = "SELECT * FROM student";
//获取执行sql语句的对象statement
statement = connection.createStatement();
//执行sql语句,获取结果集
resultSet = statement.executeQuery(sql);
//遍历获取到的结果集
while (resultSet.next()) {
int id = resultSet.getInt(1);
String name = resultSet.getString(2);
Double score = resultSet.getDouble(3);
Student student = new Student();
student.setId(id);
student.setName(name);
student.setScore(score);
System.out.println(student.toString());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
//释放资源,后调用的先释放
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
//运行结果
Student{id=1, name='张三', score=98.0}
Student{id=2, name='李四', score=96.0}
Student{id=3, name='王五', score=100.0}
ここでは詳細に上記で使用されるさまざまなオブジェクトを説明するために始めます
(C)JDBCは詳細オブジェクト
(1)のDriverManager
A:ロードドライバ - >登録ドライブ
まず、我々はドライバーと登録ドライブをロードするために知っておく必要があるすべての接触したときの単語が何を意味するか、両方の、ちょうど、誰かが常に友人になるのClass.forName(com.mysql.jdbc.Driver)
登録データベース駆動型の文としてではなく、実際にはない場合、その役割はにパラメトリック表現をロードすることですメモリと初期化、及び前記静的変数は静的コードブロックが実行され、初期化されます
疑問に思う:あなたはClassLoaderクラスのloadClass()メソッドを使用することはできますか?
- 答えはノー、この方法の特徴は、クラスの初期化をロードされていないがされて
//Class类源码节选 -jdk8
* A call to {@code forName("X")} causes the class named
* {@code X} to be initialized.
初期化の問題は、ここで簡単にそれを言及について、我々はまだ私達のメインラインに戻って来ています
クラスを初期化しないのはなぜ、あなたはそれを選択することはできませんか?
本当のためです登録ドライブ(データベースドライバのjarファイルを使用するように指示します)、次のとおりです。
static void registerDriver(Driver driver)
このカテゴリでは、我々は、ドライバのJARパッケージを見つけるのソースコードを表示します
//com.mysql.jdbc.Driver类中的静态代码块
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
クラスがロードされた後、DriverManagerクラスの静的メソッドはドライバを登録し、実行
我々はまた、2以下のコードを見ているかもしれないが、実際にドライブが二回ロードされ、実行のために
new com.mysql.jdbc.Driver()
ドライバがロードされています
//1.推荐
Class.forName("com.mysql.jdbc.Driver");
//2.不推荐
DriverManager.registerDriver(new com.mysql.jdbc.Driver())
では、なぜそれをわざわざ?new com.mysql.jdbc.Driver()
直接書き込みませんまだかなり良いですか?
しかし、我々は拒否することにしました!なぜ?
静的コードブロックを確保するために、両方の、我々は、比較的重い依存のjarパッケージを書き、そして私たちはプロジェクトの数、またはデータベースを変更する必要性に直面している場合、あなたはコードを変更する必要があり、再コンパイルしていますが、クラスのクラスローディングを使用している場合であれば含まれる登録の駆動方法は、実行されますが、文字列へのパラメータは、あなたがで設定ファイル「内容」を変更することができます+私たちが問題に対処した後に、より柔軟な方法のjarパッケージを追加し、必要としません。再コンパイル!
注:登録がドライブした後にドライバのjarパッケージMYSQL5このステップは、JARパッケージMETA-INF /サービス/に、java.sql.driverファイルに調べることにより省略することができます
com.mysql.jdbc.Driver
com.mysql.fabric.jdbc.FabricMySQLDriver
B:データベース接続
static Connection getConnection(String url, String user, String password)
/*
jdbc:mysql://ip地址(域名):端口号/数据库名称
Eg:jdbc:mysql://localhost:3306/db1
本地mysql,且端口为默认3306,则可简写:jdbc:mysql:///数据库名称
*/
(2)接続(データベース接続オブジェクト)
:SQLのオブジェクトの実行を取得します。
//创建向数据库发送sql语句的statement对象
Statement createStatement()
//创建向数据库发送预编译sql语句的PrepareStement对象
PreparedStatement prepareStatement(String sql)
B:管理サービス
//开启事务:设置参数为false,即开启事务
setAutoCommit(boolean autoCommit)
//提交事务
commit()
//回滚事务
rollback()
(3)ステートメント(SQL文を実行するためのオブジェクト)
//执行DQL(查询数据库中表的记录(数据))
ResultSet executeQuery(String sql)
//执行DML(对数据库中表的数据进行增删改)
int executeUpdate(String sql)
//执行任意sql语句,但是目标不够明确,较少使用
boolean execute(String sql)
//把多条sql的语句放到同一个批处理中
addBatch(String sql)
//向数据库总发送一批sql语句执行
executeBatch()
コードは、(例えば、データを追加すること)を示します
package cn.ideal.jdbc;
import java.sql.*;
public class StatementDemo {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
try {
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
//获取数据库连接对象
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "root99");
//定义sql语句
String sql = "INSERT student(id,NAME,score) VALUES (NULL,'马六',88);";
//获取执行sql语句的对象
statement = connection.createStatement();
//执行sql语句
int count = statement.executeUpdate(sql);
System.out.println(count);
if (count > 0) {
System.out.println("添加成功");
} else {
System.out.println("添加失败");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
if(statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
(4)のResultSet(結果セットオブジェクト、カプセル化クエリ結果)
その結果、excuteQueryを実行するStatementオブジェクト()は、ResultSetオブジェクトを返す - ResultSetがSQLステートメントの結果セットを表します
//游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据)
//如果是,则返回false,如果不是则返回true
boolean next()
//获取数据,Xxx代表数据类型
getXxx(参数)
Eg:int getInt() , String getString()
1. int:代表列的编号,从1开始 如: getString(1)
2. String:代表列名称。 如: getDouble("name")
クイックリファレンス部分を開始する場合であってもよいし、データベースに独自のデータを読み取るしようとする試みは、フレームのセットがロードされます
(D)乗算器 - ツール
情報をより直感的かつ保守が容易になるように、ツールのより一般的なクラスの出現は、我々は、プロパティをプロファイルすることができるように、いくつかの手段によってカプセル化
package cn.ideal.jdbc;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;
public class JDBCUtils {
private static String url;
private static String user;
private static String password;
private static String driver;
/**
* 文件读取
*/
static {
try {
//创建Properties集合类
Properties pro = new Properties();
//获取src路径下的文件
ClassLoader classLoader = JDBCUtils.class.getClassLoader();
URL res = classLoader.getResource("jdbc.properties");
String path = res.getPath();
//加载文件
pro.load(new FileReader(path));
//获取数据
url = pro.getProperty("url");
user = pro.getProperty("user");
password = pro.getProperty("password");
driver = pro.getProperty("driver");
//注册驱动
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取连接
*
* @return 连接对象
*/
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
/**
* 释放资源
*
* @param statement
* @param connection
*/
public static void close(Statement statement, Connection connection) {
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 释放资源
*
* @param resultSet
* @param statement
* @param connection
*/
public static void close(ResultSet resultSet, Statement statement, Connection connection) {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
ツールテストクラス
package cn.ideal.jdbc;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCUtilsTest {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
try {
connection = JDBCUtils.getConnection();
//定义sql语句
String sql = "INSERT student(id,NAME,score) VALUES (NULL,'马六',88)";
//获取执行sql语句的对象
statement = connection.createStatement();
//执行sql语句
int count = statement.executeUpdate(sql);
System.out.println(count);
if (count > 0) {
System.out.println("添加成功");
} else {
System.out.println("添加失败");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.close(statement,connection);
}
}
}
セットによって、前の記事では達成された、IOの実装、およびデータベースを学習した後、我々は、ストア・データベースのデータにしてみてください簡単なログインが少しケースを登録して書くことができます!5番目に大きい点述べ轟音で
(E)補足:PreparedStatment
//创建向数据库发送预编译sql语句的prepareStatement
PreparedStatement prepareStatement(String sql)
prepareStatementは、すべてのすべてで、それはその親、より強く、よりシンプルに比較され、声明から継承されました!
(1)効果
:効率
ステートメントは、直接のPreparedStatementう繰り返したSQL文を実行する実行するためにデータベースに直接SQLステートメントをコンパイルし、かつプリコンパイルされたSQLの場合、充填パラメータは、これはより効率的(であろうのPreparedStatementに格納されたプリコンパイル済みSQL)
B:読みやすさ
カスタムSQL文、私は多くの場合、Javaで変数を使用する必要があり、いくつかの複雑なケースでは、問題と単一引用符、より多くの変数を頻繁に使用する必要性、より複雑な、とのPreparedStatementができるプレースホルダを使用します " ?「代わりのパラメータで、そして、それは良いコードの可読性次のパラメータの割り当てであります
C:セキュリティ
プリコンパイルされたPreparedStatement回避声明のための文字列と変数を連結講ずるよう要求することができる[パスワードをバイパスして、永遠に式を記述すること] SQLインジェクション攻撃につながります
最初のテーブルを作成し、簡単なログインデモを書き、私たちの前の練習に従ってみましょう!
CREATE TABLE USER(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(32),
PASSWORD VARCHAR(32)
);
SELECT * FROM USER;
INSERT INTO USER VALUES(NULL,'admin','admin888');
INSERT INTO USER VALUES(NULL,'zhangsan','123456');
次に、コードを書きます
package cn.ideal.login;
import cn.ideal.jdbc.JDBCUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
public class LoginDemo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名");
String username = sc.nextLine();
System.out.println("请输入密码");
String password = sc.nextLine();
boolean flag = new LoginDemo().login(username, password);
if (flag) {
System.out.println("登录成功");
} else {
System.out.println("用户名或密码错误");
}
}
/**
* 登录方法
*/
public boolean login(String username, String password) {
if (username == null || password == null) {
return false;
}
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JDBCUtils.getConnection();
//定义sql
String sql = "SELECT * FROM USER WHERE username = '" + username + "' AND password = '" + password + "' ";
//获取执行sql的对象
statement = connection.createStatement();
//执行查询
resultSet = statement.executeQuery(sql);
return resultSet.next();
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtils.close(resultSet,statement, connection);
}
return false;
}
}
脆弱性はまだかなり一般的であるとき、単純にこのような単純なログインデモが書かれた、置くが、この時間は、状況はSQLインジェクションの問題を生じ、おそらくあなたは、早い時期に、聞きました私たちは今日、この種の話をしていることが多い標的部位の背景のSQLインジェクションの侵入の何らかの手段を使用する一部のハッカーやスクリプトキディは、彼はそれらの一つであり、普遍的なSQLインジェクション(SQLユニバーサルパスワード)と呼ばれます
のは、SQLステートメントのセクションで上記のコードを見てみましょう
String sql = "SELECT * FROM USER WHERE username = '" + username + "' AND password = '" + password + "' ";
我々は、入力されることusername
とpassword
データベースフィールドが間違いの代わりに存在していないが、SQLインジェクションの脆弱性のためのプログラムは、特別な文字列を構築することにより、それができる、そこにあるようなSQLクエリを、合成し、ログオンします目的は、最初のテスト結果を掲載しました
//运行结果
请输入用户名
admin
请输入密码
1' or '1' = '1
登录成功
我々は上記のコードのパスワード(ユーザー名)を取る場合は代わりに私たちのコンテンツの彼らとの一部は、どのようにそれの一種であります
String sql = "SELECT * FROM USER WHERE username = 'admin' AND PASSWORD = '1' or '1' = '1' ";
注:SQL文のロジックではオペレータは、優先度、優先度=とし、優先度を持ちますか、
したがって、上記の式および先に実行され、もちろん、リターンエラー、または実行部は、その後、戻り値の永久「1」=「1」の式が常に真であるので、SQLクエリの結果、すなわち、ログ、真であります成功
//使用PrepareStemen替代主要部分
//定义sql
String sql = "SELECT * FROM USER WHERE username = ? AND password = ?";
//获取执行sql的对象
preparedStatement = connection.prepareStatement(sql);
//给?赋值
preparedStatement.setString(1, username);
preparedStatement.setString(2, password);
//执行查询
resultSet = preparedStatement.executeQuery();
//运行结果
请输入用户名
admin
请输入密码
1' or '1' = '1
用户名或密码错误
終了:
間違った場所に不備、またはコンテンツがある場合は、私に叫ぶのアドバイス、カニのみんなを与えることを歓迎します!^ _ ^
あなたが助けることができるなら、それは私に注意を払うことです!(記事の更新シリーズは初めて公衆の数になります)
ここでは、すべて自分のための夢や仕事で、見知らぬ人です❤
2の上に10日以上:スティック元のJavaテクノロジのパブリック番号を押してください