ตามที่คนอื่น ๆ ระบุไว้รหัสของคุณนั้นถูกต้องแล้วแม้ว่าส่วนนอกtry
นั้นไม่จำเป็น นี่คือความคิดอีกไม่กี่
DataSource
คำตอบอื่น ๆ ที่นี่ถูกต้องและดีเช่นคำตอบที่ยอมรับโดย bpgergo แต่ไม่มีการใช้งานDataSource
ที่แนะนำโดยทั่วไปแนะนำให้ใช้มากกว่าDriverManager
ในจาวาที่ทันสมัย
ดังนั้นเพื่อความสมบูรณ์นี่คือตัวอย่างที่สมบูรณ์ที่ดึงข้อมูลวันที่ปัจจุบันจากเซิร์ฟเวอร์ฐานข้อมูล ฐานข้อมูลที่ใช้ที่นี่เป็นPostgres ฐานข้อมูลอื่นจะทำงานในทำนองเดียวกัน คุณจะแทนที่การใช้org.postgresql.ds.PGSimpleDataSource
ด้วยการใช้งานDataSource
ที่เหมาะสมกับฐานข้อมูลของคุณ อาจมีการนำไปใช้โดยไดรเวอร์เฉพาะหรือพูลการเชื่อมต่อหากคุณไปเส้นทางนั้น
DataSource
การดำเนินการต้องไม่ถูกปิดเพราะมันจะไม่“เปิด” A DataSource
ไม่ใช่ทรัพยากรไม่ได้เชื่อมต่อกับฐานข้อมูลดังนั้นจึงไม่ถือการเชื่อมต่อเครือข่ายหรือทรัพยากรบนเซิร์ฟเวอร์ฐานข้อมูล A DataSource
เป็นเพียงข้อมูลที่จำเป็นเมื่อทำการเชื่อมต่อกับฐานข้อมูลด้วยชื่อเครือข่ายหรือที่อยู่ของเซิร์ฟเวอร์ฐานข้อมูลชื่อผู้ใช้รหัสผ่านผู้ใช้และตัวเลือกต่าง ๆ ที่คุณต้องการระบุเมื่อทำการเชื่อมต่อในที่สุด ดังนั้นDataSource
วัตถุที่ใช้งานของคุณจะไม่เข้าไปในวงเล็บลองกับทรัพยากร
ซ้อนกันลองกับทรัพยากร
รหัสของคุณใช้อย่างเหมาะสมกับคำสั่งลองกับทรัพยากรที่ซ้อนกัน
โปรดสังเกตในรหัสตัวอย่างด้านล่างว่าเรายังใช้ไวยากรณ์ลองกับทรัพยากรสองครั้งซ้อนกันภายในอีก ด้านนอกtry
กำหนดสองทรัพยากร: และConnection
PreparedStatement
ภายในtry
กำหนดResultSet
ทรัพยากร นี่คือโครงสร้างรหัสทั่วไป
หากมีข้อผิดพลาดถูกโยนออกมาจากภายในและไม่ถูกจับที่นั่นResultSet
ทรัพยากรจะถูกปิดโดยอัตโนมัติ (ถ้ามีอยู่จะไม่เป็นโมฆะ) หลังจากนั้นPreparedStatement
จะปิดและสุดท้ายConnection
ปิด ทรัพยากรถูกปิดโดยอัตโนมัติในลำดับย้อนกลับที่ประกาศในคำสั่งลองกับทรัพยากร
ตัวอย่างโค้ดที่นี่เรียบง่ายเกินไป ตามที่เขียนไว้มันสามารถดำเนินการได้ด้วยคำสั่งลองกับทรัพยากร แต่ในการทำงานจริงคุณอาจทำงานได้มากขึ้นระหว่างการtry
โทรที่ซ้อนกัน ตัวอย่างเช่นคุณอาจกำลังดึงค่าจากส่วนติดต่อผู้ใช้หรือ POJO ของคุณแล้วส่งค่าเหล่านั้นเพื่อเติม?
เต็มตัวยึดตำแหน่งภายใน SQL ของคุณผ่านการเรียกไปยังPreparedStatement::set…
เมธอด
บันทึกไวยากรณ์
อัฒภาคต่อท้าย
ขอให้สังเกตว่าเครื่องหมายอัฒภาคต่อท้ายคำสั่งทรัพยากรล่าสุดภายในวงเล็บของ try-with-resources เป็นทางเลือก ฉันรวมไว้ในงานของฉันเองด้วยเหตุผลสองประการ: ความสอดคล้องและดูสมบูรณ์และทำให้การคัดลอกวางการผสมของบรรทัดง่ายขึ้นโดยไม่ต้องกังวลเกี่ยวกับอัฒภาคปลายเส้น IDE ของคุณอาจตั้งค่าเซมิโคลอนล่าสุดเป็นฟุ่มเฟือย แต่ไม่มีอันตรายใด ๆ
Java 9 - ใช้ vars ที่มีอยู่ในลองกับทรัพยากร
ใหม่ใน Java 9คือการปรับปรุงไวยากรณ์ลองกับทรัพยากร ตอนนี้เราสามารถประกาศและเติมทรัพยากรที่อยู่นอกวงเล็บของtry
คำสั่ง ฉันยังไม่พบสิ่งนี้มีประโยชน์สำหรับทรัพยากร JDBC แต่จำไว้ในการทำงานของคุณเอง
ResultSet
ควรปิดตัวเอง แต่อาจไม่
ในโลกอุดมคติที่ResultSet
จะปิดตัวเองเป็นเอกสารสัญญา:
วัตถุ ResultSet จะถูกปิดโดยอัตโนมัติเมื่อวัตถุ Statement ที่สร้างมันถูกปิดดำเนินการใหม่หรือใช้เพื่อดึงผลลัพธ์ต่อไปจากลำดับของผลลัพธ์หลายรายการ
น่าเสียดายที่ในอดีตไดรเวอร์ JDBC บางตัวล้มเหลวอย่างน่าอับอายที่จะทำตามสัญญานี้ เป็นผลให้โปรแกรมเมอร์ JDBC จำนวนมากได้เรียนรู้อย่างชัดเจนใกล้ทรัพยากรทั้งหมดของพวกเขารวมทั้ง JDBC Connection
, PreparedStatement
และResultSet
มากเกินไป ไวยากรณ์ try-with-resources ที่ทันสมัยทำให้การทำง่ายขึ้นและใช้โค้ดขนาดกะทัดรัดยิ่งขึ้น ขอให้สังเกตว่าทีม Java ไปยุ่งเกี่ยวResultSet
กับการทำเครื่องหมายเป็นAutoCloseable
และฉันขอแนะนำให้เราใช้มัน การใช้การลองกับทรัพยากรรอบ ๆ ทรัพยากร JDBC ทั้งหมดของคุณจะทำให้โค้ดของคุณจัดทำเอกสารด้วยตนเองมากขึ้นตามความตั้งใจของคุณ
ตัวอย่างรหัส
package work.basil.example;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate;
import java.util.Objects;
public class App
{
public static void main ( String[] args )
{
App app = new App();
app.doIt();
}
private void doIt ( )
{
System.out.println( "Hello World!" );
org.postgresql.ds.PGSimpleDataSource dataSource = new org.postgresql.ds.PGSimpleDataSource();
dataSource.setServerName( "1.2.3.4" );
dataSource.setPortNumber( 5432 );
dataSource.setDatabaseName( "example_db_" );
dataSource.setUser( "scott" );
dataSource.setPassword( "tiger" );
dataSource.setApplicationName( "ExampleApp" );
System.out.println( "INFO - Attempting to connect to database: " );
if ( Objects.nonNull( dataSource ) )
{
String sql = "SELECT CURRENT_DATE ;";
try (
Connection conn = dataSource.getConnection() ;
PreparedStatement ps = conn.prepareStatement( sql ) ;
)
{
… make `PreparedStatement::set…` calls here.
try (
ResultSet rs = ps.executeQuery() ;
)
{
if ( rs.next() )
{
LocalDate ld = rs.getObject( 1 , LocalDate.class );
System.out.println( "INFO - date is " + ld );
}
}
}
catch ( SQLException e )
{
e.printStackTrace();
}
}
System.out.println( "INFO - all done." );
}
}
try (ResultSet rs = ps.executeQuery()) {
เพราะวัตถุ ResultSet ถูกปิดโดยอัตโนมัติโดยวัตถุ Statement ที่สร้างมันขึ้นมา