ラージオブジェクトの Lob フィールドの処理
実際には、Lob には 2 つのタイプがあります。1 つは大きなテキストを格納するためのフィールド Clob で、もう 1 つは大量のバイナリ データを格納するためのフィールド Blob です。データベースが異なれば処理方法も若干異なり、大きなフィールドは一般にストリームの形式で処理されます。
ラージ フィールド タイプ (一般に LOB フィールド) には大量のデータが格納されるため、サブテーブル ストレージの方法が使用されます。
要件: 学生情報の保存、学生の写真の保存が必要
- 生徒の写真をファイル システムに保存します。実際のデータには写真へのパスのみが保存されます。
- 画像の暗号化が必要な場合、ファイル システムに保存するのは不合理です
- DBMSが提供する圧縮暗号化機能を利用してデータテーブルにデータを格納できます。
特に保管されている場合は?
- 大規模なフィールド データではなく、関連する基本情報をテーブルに格納します
- 大きなフィールド データを 1 つのテーブルに保存する
クローブ
MySQL の Clob のデータ型
- tinytext は最大 255 文字を保存できます
- テキストには最大 65535 文字を保存できます
- メディアテキストは最大 1,600 万文字を保存できます
- 長文は最大 4G 文字を保存できます
テーブルの作成
-- 学生的基本信息
create table tb_student(
id bigint primary key auto_increment,
name varchar(20)
);
-- 学生表对应的大字段数据
create table tb_memo(
id bigint -- 具体实现中将其定义为外键,并且支持级联删除
memo longtext
);
-- 为了测试方便,所以将两个表合在一起
create table tb_student(
id bigint primary key auto_increment,
name varchar(20),
memo longtext
);
JDBCを使用してテーブルにデータを挿入する
//JDK1.8支持JDBC4.2,所以只要驱动支持,加载驱动的操作可以省略
/*
目前可以使用的驱动有2种,一个com.mysql.jdbc.Driver是针对
MySQL8以前的老版本的驱动,官方已经不再建议使用;如果使用
MySQL5.7+的数据库则建议使用新版本的驱动
com.mysql.cj.jdbc.Driver
*/
try (
Connection conn = DriverManager.getConnection("jdbc:mysql:///test?serverTimezone=UTC", "root", "123456");
Reader r = new BufferedReader(new FileReader("memo.txt"));) {
PreparedStatement ps = conn.prepareStatement("insert into tb_studentvalues(null,?,?)");
ps.setString(1, "张毅");
ps.setClob(2, r);
int len = ps.executeUpdate();
if (len > 0)
System.out.println("插入成功!");
else
System.out.println("插入失败!");
}
ドライバーをロードせずに、
JDBC を使用してテーブルからラージ オブジェクト タイプのフィールドを読み取ることがサポートされているかどうかを判断する方法
PreparedStatement ps = conn.prepareStatement("select * from tb_student whereid=?");
ps.setLong(1, 1);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
Long id = rs.getLong("id");
String name = rs.getString("name");
Clob clob = rs.getClob("memo");
Reader r = clob.getCharacterStream();
System.out.println(id+"\t"+name);
char[] buffer=new char[8192];
int len=0;
while((len=r.read(buffer))>0){
System.out.print(new String(buffer,0,len));
}
r.close();
}
ブロブ
BLOB は大きなバイナリ フィールド タイプであり、一般にグラフィックス、サウンド、ビデオなどのバイナリ シーケンス データを格納するために使用されます。MySQL はバイナリ ラージ オブジェクトに 4 つのデータ型を提供します
- tinyblob 上限 255
- ブロブ上限 65535
- ミディアムブロブ上限 16M
- ongblob上限4G
テーブル定義:ラージ オブジェクト タイプのフィールドは別のテーブルに保存する必要があります
alter table tb_student add image longblob;
JDBC を使用してバイナリ ラージ オブジェクト データを挿入する
InputStream is = new BufferedInputStream(new
FileInputStream("pic/xiaopang.jpg"));
PreparedStatement ps=conn.prepareStatement("update tb_student set image=? where id=?");
ps.setBlob(1, is);
ps.setLong(2, 1);
int len=ps.executeUpdate();
JDBC を使用してバイナリ ラージ オブジェクト データを取得する
PreparedStatement ps = conn.prepareStatement("select * from tb_student whereid=?");
ps.setLong(1, 1);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
Long id = rs.getLong("id");
String name = rs.getString("name");
String memo = rs.getString("memo");
System.out.println(id + "\t" + name + "\t" + memo);
Blob image = rs.getBlob("image");
InputStream is = image.getBinaryStream();
OutputStream os = new FileOutputStream("c:\\" + name + ".jpg");
byte[] buffer = new byte[8192];
int len = 0;
while((len=is.read(buffer))>0)
os.write(buffer,0,len);
os.close();
is.close();
}
操作方法補足
JDBC は Java データベース接続を指します。これは、Java プログラミング言語と幅広いデータベースを接続するために使用される、標準の Java アプリケーション プログラミング インターフェイス JAVA API です。
create table tb_student(
id bigint primary key auto_increment comment '学生编号',
name varchar(32) not null
)engine=innodb default charset utf8mb4;
自己増加するキー値を取得する
JDBC 経由でデータベース テーブルにレコードを追加し、フィールドの 1 つが self-incrementing である
id bigint primary key auto_increment
ため、追加後に JDBC 側で自己インクリメント値を直接取得する方法。
PreparedStatement は Statement のサブインターフェイスです。Statement インターフェイスには、Statement.RETURN_GENERATED_KEYS などのいくつかの定数値があります。
自動インクリメントされたキー値を追加して取得するには、次のようにします。
(1)PreparedStatement pst =conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
(2) 追加した SQL の実行が完了したら、PreparedStatement オブジェクトを通じて getGeneratedKeys() メソッドを呼び出して自己増加キー値を取得し、結果セットを走査します。
try (Connection conn = DriverManager.getConnection("jdbc:mysql:///test?
serverTimezone=UTC", "root",
"123456");) {
String sql = "insert into tb_student(name) values(?)";
// 默认不返回生成的key值,如果需要返回自增长的主键值,则需要添加一个常量值作为参数。默认值
NO_GENERATED_KEYS
PreparedStatement ps = conn.prepareStatement(sql,
Statement.RETURN_GENERATED_KEYS);
ps.setString(1, "赵小胖2");
int pos = ps.executeUpdate();
if (pos > 0) {
System.out.println("插入成功!");
//如果插入成功则会返回插入数据对应的主键值
//从ps中获取到服务器端返回的键值
ResultSet rs = ps.getGeneratedKeys();//因为这里的key值可能多个,因为insert语
句可以同时添加多行,所以用ResultSet封装
//这里因为只添加一条,所以用if判断
if(rs.next()){
Object key = rs.getObject(1);
System.out.println("自增的key值id =" + key);
}
rs.close();
} else
System.out.println("插入失败!");
ps.close();
}
バッチ処理
バッチ処理: SQL をバッチ処理します。例: 1) 注文詳細テーブルに複数のレコードを追加します。2) シミュレーションデータを一括追加する等
バッチ処理を使用しない場合とバッチ処理を使用する場合の違いは何ですか?
- バッチ処理の効率が大幅に向上します
バッチ操作をするにはどうすればよいですか?
ps.addBatch();
int[] all = ps.executeBatch();
注: バッチで追加する場合、挿入では値の代わりに値が使用されます。
try (Connection conn = DriverManager.getConnection("jdbc:mysql:///test?
serverTimezone=UTC", "root", "123456");) {
String sql = "insert into tb_student(name) values(?)";
PreparedStatement ps = conn.prepareStatement(sql);
// 一次性插入100条数据
for (int i = 0; i < 100; i++) {
ps.setString(1, "张_" + i);
ps.addBatch(); //添加到批处理一组操作中,攒一块处理
//如果一次性提交的数据量过大,允许部分提交
if(i%10==0){
int[] res=ps.executeBatch();
System.out.println(i+":"+Arrays.toString(res));
ps.clearBatch();
}
}
int[] pos = ps.executeBatch(); //执行批处理,返回各个对应处理的结果
System.out.println(Arrays.toString(pos));
ps.close();
}
バッチ処理の利点が明らかでない場合は、制限が多すぎるためバッチ処理を使用する必要はありません。
スクロール可能な結果セット
デフォルトでは、ResultSet 結果セットは一方向です。つまり、データベース内のレコードを読み取るときにレコードを 1 つずつ読み取る必要がない場合、データは rs.next メソッドを通じて一方向でのみ読み取ることができます。 、特定のニーズに応じてスキップできます。その後、いくつかのレコードが読み取られるか、前後に読み取られます。
PreparedStatement prepareStatement(String sql, int resultSetType,int
resultSetConcurrency) throws SQLException;
- パラメータ1は指定するSQL文です。
- パラメータ 2 は結果セットのタイプで、ResultSet インターフェイスで使用できる 3 つの定数値です
- TYPE_SCROLL_INSENSITIVE スクロール可能非依存
- TYPE_SCROLL_SENSITIVE スクロール可能センシティブ
- TYPE_FORWARD_ONLY 一方向スクロール、next のみ呼び出すことができます
- パラメータ 3 は、結果セットの同時実行サポートを設定するために使用されます。
- CONCUR_READ_ONLY 同時アクセス時の読み取り専用。このうち、concur は同時に発生する、つまり同時実行と訳されます。つまり、結果セットが同時にアクセスされた場合、読み取り専用アクセスのみが可能です。つまり、内部のコンテンツのみを読み取ることができ、変更はできません。作ることができる。
- CONCUR_UPDATABLE により、アクセス中の変更が可能になります
これを行うには、Statement オブジェクトの作成時に 2 つのプロパティをパラメータとして使用します。
Statement stmt =conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY)
try (Connection conn = DriverManager.getConnection("jdbc:mysql:///test?
serverTimezone=UTC", "root", "123456")) {
PreparedStatement ps = conn.prepareStatement("select * from tb_student",
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet rs = ps.executeQuery();
rs.last();// 将行指针指向到最后一行
do {
long id = rs.getLong("id");
String name = rs.getString("name");
System.out.println(id + "\t" + name);
} while (rs.previous());
rs.close();
ps.close();
}
スクロール可能な結果セット ResultSet 参照 rs を取得した後、結果セットのメソッドを使用して行ポインターを任意にスクロールできます。
- rs.last() //カーソルをレコードの最後の行に移動します
- rs.isLast() //レコードの最後の行を指しているかどうかを判断します
- rs.isAfterLast() //最後の行の上の行、つまり最後から2番目の行を指しているかどうかを判断します
- rs.getRow() // 現在のカーソルが指している行を返します
- rs.previous() //カーソルを現在指している行の前の行を指すようにします
- rs.absolute(int x) // カーソルを行 x に直接ポイントします。