or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-features.mdbasic-connectivity.mdcopy-operations.mddatasource.mdindex.mdlarge-objects.mdpostgresql-types.mdreplication.mdresultset.mdssl-security.mdstatement-execution.mdtransactions.md

statement-execution.mddocs/

0

# Statement Execution

1

2

This document covers SQL statement execution including Statement, PreparedStatement, and CallableStatement interfaces, along with PostgreSQL-specific extensions.

3

4

## Capabilities

5

6

### PGStatement Interface

7

8

PostgreSQL-specific extensions to java.sql.Statement.

9

10

```java { .api }

11

package org.postgresql;

12

13

import java.sql.Statement;

14

import java.sql.SQLException;

15

16

/**

17

* PostgreSQL extensions to java.sql.Statement.

18

* All Statement objects returned by PostgreSQL connections implement this interface.

19

*/

20

public interface PGStatement extends Statement {

21

/**

22

* Constant representing positive infinity for date/timestamp values.

23

* Corresponds to PostgreSQL's 'infinity' date value.

24

*/

25

long DATE_POSITIVE_INFINITY = 9223372036825200000L;

26

27

/**

28

* Constant representing negative infinity for date/timestamp values.

29

* Corresponds to PostgreSQL's '-infinity' date value.

30

*/

31

long DATE_NEGATIVE_INFINITY = -9223372036832400000L;

32

33

/**

34

* Smaller positive infinity value for compatibility.

35

*/

36

long DATE_POSITIVE_SMALLER_INFINITY = 185543533774800000L;

37

38

/**

39

* Smaller negative infinity value for compatibility.

40

*/

41

long DATE_NEGATIVE_SMALLER_INFINITY = -185543533774800000L;

42

43

/**

44

* Returns the OID of the last row inserted by this statement.

45

* Only valid for INSERT statements that inserted exactly one row.

46

*

47

* @return OID of last inserted row, or 0 if not applicable

48

* @throws SQLException if statement has not been executed

49

*/

50

long getLastOID() throws SQLException;

51

52

/**

53

* Sets the threshold for when to use server-side prepared statements.

54

* The statement will be prepared on the server after it has been executed

55

* this many times.

56

*

57

* @param threshold Number of executions before server prepare:

58

* - Positive value N: Use server prepare on Nth and subsequent executions

59

* - 0: Never use server prepare

60

* - Negative: Reserved for internal use (forceBinary mode)

61

* - Default: 5 (configurable via prepareThreshold connection property)

62

* @throws SQLException if threshold cannot be set

63

*/

64

void setPrepareThreshold(int threshold) throws SQLException;

65

66

/**

67

* Gets the current prepare threshold for this statement.

68

*

69

* @return Current prepare threshold

70

*/

71

int getPrepareThreshold();

72

73

/**

74

* Turn on the use of prepared statements in the server.

75

* Server-side prepared statements are unrelated to JDBC PreparedStatements.

76

* As of build 302, this method is equivalent to setPrepareThreshold(1).

77

*

78

* @param flag use server prepare

79

* @throws SQLException if something goes wrong

80

* @deprecated As of build 302, replaced by setPrepareThreshold(int)

81

*/

82

@Deprecated

83

void setUseServerPrepare(boolean flag) throws SQLException;

84

85

/**

86

* Returns whether server-side prepare will be used for this statement.

87

* A return value of true indicates that the next execution will use

88

* a server-prepared statement, assuming the protocol supports it.

89

*

90

* @return true if next reuse will use server prepare

91

*/

92

boolean isUseServerPrepare();

93

94

/**

95

* Enables or disables adaptive fetch size adjustment.

96

* When enabled, the driver automatically adjusts fetch size based on

97

* available memory and result set characteristics.

98

*

99

* @param adaptiveFetch true to enable adaptive fetch

100

*/

101

void setAdaptiveFetch(boolean adaptiveFetch);

102

103

/**

104

* Returns whether adaptive fetch is enabled for this statement.

105

*

106

* @return true if adaptive fetch is enabled

107

*/

108

boolean getAdaptiveFetch();

109

}

110

```

111

112

**Usage Examples:**

113

114

```java

115

import org.postgresql.PGStatement;

116

import java.sql.Connection;

117

import java.sql.DriverManager;

118

import java.sql.Statement;

119

import java.sql.ResultSet;

120

import java.sql.SQLException;

121

122

// Example 1: Basic Statement usage

123

public class BasicStatementExample {

124

public static void executeQuery(Connection conn) throws SQLException {

125

try (Statement stmt = conn.createStatement()) {

126

// Execute a simple query

127

try (ResultSet rs = stmt.executeQuery("SELECT id, name FROM users")) {

128

while (rs.next()) {

129

System.out.println(rs.getInt("id") + ": " + rs.getString("name"));

130

}

131

}

132

}

133

}

134

}

135

136

// Example 2: Get last inserted OID

137

public class OIDExample {

138

public static void insertAndGetOID(Connection conn) throws SQLException {

139

try (Statement stmt = conn.createStatement()) {

140

// Insert a row

141

int rowsAffected = stmt.executeUpdate(

142

"INSERT INTO documents (title, content) VALUES ('Doc1', 'Content')");

143

144

// Get OID of inserted row (only works if table has OIDs)

145

PGStatement pgStmt = stmt.unwrap(PGStatement.class);

146

long oid = pgStmt.getLastOID();

147

System.out.println("Inserted row OID: " + oid);

148

}

149

}

150

}

151

152

// Example 3: Configure prepare threshold

153

public class PrepareThresholdExample {

154

public static void configurePrepare(Connection conn) throws SQLException {

155

try (Statement stmt = conn.createStatement()) {

156

PGStatement pgStmt = stmt.unwrap(PGStatement.class);

157

158

// Set to prepare immediately

159

pgStmt.setPrepareThreshold(0);

160

161

// Or never prepare (always use simple protocol)

162

// pgStmt.setPrepareThreshold(-1);

163

164

// Execute query

165

try (ResultSet rs = stmt.executeQuery("SELECT * FROM users")) {

166

// process results

167

}

168

}

169

}

170

}

171

172

// Example 4: Statement with fetch size

173

public class FetchSizeExample {

174

public static void queryWithFetchSize(Connection conn) throws SQLException {

175

try (Statement stmt = conn.createStatement()) {

176

// Set fetch size to retrieve rows in batches of 100

177

stmt.setFetchSize(100);

178

179

// Execute large query

180

try (ResultSet rs = stmt.executeQuery("SELECT * FROM large_table")) {

181

while (rs.next()) {

182

// Process rows - driver fetches 100 at a time

183

}

184

}

185

}

186

}

187

}

188

189

// Example 5: Batch updates

190

public class BatchUpdateExample {

191

public static void batchInsert(Connection conn) throws SQLException {

192

try (Statement stmt = conn.createStatement()) {

193

// Add multiple statements to batch

194

stmt.addBatch("INSERT INTO logs (message) VALUES ('Log 1')");

195

stmt.addBatch("INSERT INTO logs (message) VALUES ('Log 2')");

196

stmt.addBatch("INSERT INTO logs (message) VALUES ('Log 3')");

197

198

// Execute all at once

199

int[] results = stmt.executeBatch();

200

System.out.println("Inserted " + results.length + " rows");

201

}

202

}

203

}

204

```

205

206

### PreparedStatement

207

208

Precompiled SQL statements with parameter support.

209

210

```java { .api }

211

import java.sql.PreparedStatement;

212

import java.sql.SQLException;

213

import java.sql.Date;

214

import java.sql.Timestamp;

215

import java.sql.Array;

216

import java.io.InputStream;

217

import java.io.Reader;

218

219

/**

220

* PreparedStatement represents a precompiled SQL statement.

221

* PostgreSQL driver implements full JDBC PreparedStatement interface

222

* with extensions from PGStatement.

223

*/

224

public interface PreparedStatement extends Statement {

225

/**

226

* Executes the SQL query and returns a ResultSet.

227

*

228

* @return ResultSet containing query results

229

* @throws SQLException if execution fails

230

*/

231

ResultSet executeQuery() throws SQLException;

232

233

/**

234

* Executes an SQL INSERT, UPDATE, or DELETE statement.

235

*

236

* @return Number of rows affected

237

* @throws SQLException if execution fails

238

*/

239

int executeUpdate() throws SQLException;

240

241

/**

242

* Executes any SQL statement.

243

*

244

* @return true if result is a ResultSet, false if update count or no result

245

* @throws SQLException if execution fails

246

*/

247

boolean execute() throws SQLException;

248

249

// Parameter setters

250

251

/**

252

* Sets a parameter to SQL NULL.

253

*

254

* @param parameterIndex Parameter index (1-based)

255

* @param sqlType SQL type code from java.sql.Types

256

* @throws SQLException if index is invalid

257

*/

258

void setNull(int parameterIndex, int sqlType) throws SQLException;

259

260

/**

261

* Sets a boolean parameter.

262

*/

263

void setBoolean(int parameterIndex, boolean x) throws SQLException;

264

265

/**

266

* Sets a byte parameter.

267

*/

268

void setByte(int parameterIndex, byte x) throws SQLException;

269

270

/**

271

* Sets a short parameter.

272

*/

273

void setShort(int parameterIndex, short x) throws SQLException;

274

275

/**

276

* Sets an int parameter.

277

*/

278

void setInt(int parameterIndex, int x) throws SQLException;

279

280

/**

281

* Sets a long parameter.

282

*/

283

void setLong(int parameterIndex, long x) throws SQLException;

284

285

/**

286

* Sets a float parameter.

287

*/

288

void setFloat(int parameterIndex, float x) throws SQLException;

289

290

/**

291

* Sets a double parameter.

292

*/

293

void setDouble(int parameterIndex, double x) throws SQLException;

294

295

/**

296

* Sets a BigDecimal parameter.

297

*/

298

void setBigDecimal(int parameterIndex, java.math.BigDecimal x) throws SQLException;

299

300

/**

301

* Sets a String parameter.

302

*/

303

void setString(int parameterIndex, String x) throws SQLException;

304

305

/**

306

* Sets a byte array parameter.

307

*/

308

void setBytes(int parameterIndex, byte[] x) throws SQLException;

309

310

/**

311

* Sets a Date parameter.

312

*/

313

void setDate(int parameterIndex, Date x) throws SQLException;

314

315

/**

316

* Sets a Time parameter.

317

*/

318

void setTime(int parameterIndex, java.sql.Time x) throws SQLException;

319

320

/**

321

* Sets a Timestamp parameter.

322

*/

323

void setTimestamp(int parameterIndex, Timestamp x) throws SQLException;

324

325

/**

326

* Sets a parameter from an InputStream (for large text/binary data).

327

*/

328

void setBinaryStream(int parameterIndex, InputStream x, int length)

329

throws SQLException;

330

331

/**

332

* Sets a parameter from a Reader (for large character data).

333

*/

334

void setCharacterStream(int parameterIndex, Reader reader, int length)

335

throws SQLException;

336

337

/**

338

* Sets an Object parameter with automatic type mapping.

339

*/

340

void setObject(int parameterIndex, Object x) throws SQLException;

341

342

/**

343

* Sets an Object parameter with target SQL type.

344

*/

345

void setObject(int parameterIndex, Object x, int targetSqlType)

346

throws SQLException;

347

348

/**

349

* Sets an Array parameter.

350

*/

351

void setArray(int parameterIndex, Array x) throws SQLException;

352

353

/**

354

* Clears all parameter values.

355

*/

356

void clearParameters() throws SQLException;

357

358

/**

359

* Adds a set of parameters to the batch.

360

* Call after setting all parameters for one execution.

361

*/

362

void addBatch() throws SQLException;

363

}

364

```

365

366

**Usage Examples:**

367

368

```java

369

import java.sql.Connection;

370

import java.sql.PreparedStatement;

371

import java.sql.ResultSet;

372

import java.sql.SQLException;

373

import java.sql.Date;

374

import java.sql.Timestamp;

375

376

// Example 1: Basic PreparedStatement

377

public class BasicPreparedStatement {

378

public static void queryWithParameters(Connection conn) throws SQLException {

379

String sql = "SELECT id, name, email FROM users WHERE active = ? AND created_date > ?";

380

381

try (PreparedStatement pstmt = conn.prepareStatement(sql)) {

382

// Set parameters (1-based indexing)

383

pstmt.setBoolean(1, true);

384

pstmt.setDate(2, Date.valueOf("2024-01-01"));

385

386

try (ResultSet rs = pstmt.executeQuery()) {

387

while (rs.next()) {

388

System.out.println(rs.getInt("id") + ": " + rs.getString("name"));

389

}

390

}

391

}

392

}

393

}

394

395

// Example 2: INSERT with PreparedStatement

396

public class InsertExample {

397

public static void insertUser(Connection conn, String name, String email)

398

throws SQLException {

399

String sql = "INSERT INTO users (name, email, created_at) VALUES (?, ?, ?)";

400

401

try (PreparedStatement pstmt = conn.prepareStatement(sql)) {

402

pstmt.setString(1, name);

403

pstmt.setString(2, email);

404

pstmt.setTimestamp(3, new Timestamp(System.currentTimeMillis()));

405

406

int rowsAffected = pstmt.executeUpdate();

407

System.out.println("Inserted " + rowsAffected + " row(s)");

408

}

409

}

410

}

411

412

// Example 3: Batch INSERT with PreparedStatement

413

public class BatchInsertExample {

414

public static void batchInsert(Connection conn, List<User> users)

415

throws SQLException {

416

String sql = "INSERT INTO users (name, email) VALUES (?, ?)";

417

418

try (PreparedStatement pstmt = conn.prepareStatement(sql)) {

419

for (User user : users) {

420

pstmt.setString(1, user.getName());

421

pstmt.setString(2, user.getEmail());

422

pstmt.addBatch(); // Add to batch

423

}

424

425

// Execute all inserts at once

426

int[] results = pstmt.executeBatch();

427

System.out.println("Batch inserted " + results.length + " rows");

428

}

429

}

430

}

431

432

// Example 4: Handling NULL values

433

public class NullHandlingExample {

434

public static void insertWithNulls(Connection conn) throws SQLException {

435

String sql = "INSERT INTO products (name, description, price) VALUES (?, ?, ?)";

436

437

try (PreparedStatement pstmt = conn.prepareStatement(sql)) {

438

pstmt.setString(1, "Product A");

439

pstmt.setNull(2, java.sql.Types.VARCHAR); // NULL description

440

pstmt.setBigDecimal(3, new java.math.BigDecimal("19.99"));

441

442

pstmt.executeUpdate();

443

}

444

}

445

}

446

447

// Example 5: Reusing PreparedStatement

448

public class ReusePreparedStatement {

449

public static void insertMultiple(Connection conn) throws SQLException {

450

String sql = "INSERT INTO logs (level, message) VALUES (?, ?)";

451

452

try (PreparedStatement pstmt = conn.prepareStatement(sql)) {

453

// First execution

454

pstmt.setString(1, "INFO");

455

pstmt.setString(2, "Application started");

456

pstmt.executeUpdate();

457

458

// Clear and set new values

459

pstmt.clearParameters();

460

pstmt.setString(1, "DEBUG");

461

pstmt.setString(2, "Debug message");

462

pstmt.executeUpdate();

463

}

464

}

465

}

466

467

// Example 6: Binary data

468

public class BinaryDataExample {

469

public static void insertBinaryData(Connection conn, byte[] imageData)

470

throws SQLException {

471

String sql = "INSERT INTO images (name, data) VALUES (?, ?)";

472

473

try (PreparedStatement pstmt = conn.prepareStatement(sql)) {

474

pstmt.setString(1, "photo.jpg");

475

pstmt.setBytes(2, imageData);

476

pstmt.executeUpdate();

477

}

478

}

479

}

480

481

// Example 7: PostgreSQL arrays

482

public class ArrayExample {

483

public static void insertArray(Connection conn) throws SQLException {

484

String sql = "INSERT INTO documents (tags) VALUES (?)";

485

486

try (PreparedStatement pstmt = conn.prepareStatement(sql)) {

487

// Create PostgreSQL array

488

String[] tags = {"java", "postgresql", "jdbc"};

489

Array sqlArray = conn.createArrayOf("text", tags);

490

491

pstmt.setArray(1, sqlArray);

492

pstmt.executeUpdate();

493

494

sqlArray.free();

495

}

496

}

497

}

498

```

499

500

### CallableStatement

501

502

Support for calling PostgreSQL functions and procedures.

503

504

```java { .api }

505

import java.sql.CallableStatement;

506

import java.sql.SQLException;

507

import java.sql.Types;

508

509

/**

510

* CallableStatement is used to execute stored procedures and functions.

511

* PostgreSQL driver provides full support for calling database functions.

512

*/

513

public interface CallableStatement extends PreparedStatement {

514

/**

515

* Registers an OUT parameter for a stored procedure.

516

*

517

* @param parameterIndex Parameter index (1-based)

518

* @param sqlType SQL type code from java.sql.Types

519

* @throws SQLException if registration fails

520

*/

521

void registerOutParameter(int parameterIndex, int sqlType) throws SQLException;

522

523

/**

524

* Registers an OUT parameter with specific type name.

525

*

526

* @param parameterIndex Parameter index

527

* @param sqlType SQL type code

528

* @param typeName PostgreSQL type name

529

* @throws SQLException if registration fails

530

*/

531

void registerOutParameter(int parameterIndex, int sqlType, String typeName)

532

throws SQLException;

533

534

/**

535

* Indicates whether the last OUT parameter read had value SQL NULL.

536

*

537

* @return true if last parameter was NULL

538

* @throws SQLException if check fails

539

*/

540

boolean wasNull() throws SQLException;

541

542

/**

543

* Retrieves a String OUT parameter.

544

*/

545

String getString(int parameterIndex) throws SQLException;

546

547

/**

548

* Retrieves a boolean OUT parameter.

549

*/

550

boolean getBoolean(int parameterIndex) throws SQLException;

551

552

/**

553

* Retrieves an int OUT parameter.

554

*/

555

int getInt(int parameterIndex) throws SQLException;

556

557

/**

558

* Retrieves a long OUT parameter.

559

*/

560

long getLong(int parameterIndex) throws SQLException;

561

562

/**

563

* Retrieves a double OUT parameter.

564

*/

565

double getDouble(int parameterIndex) throws SQLException;

566

567

/**

568

* Retrieves an Object OUT parameter.

569

*/

570

Object getObject(int parameterIndex) throws SQLException;

571

572

/**

573

* Retrieves an Array OUT parameter.

574

*/

575

java.sql.Array getArray(int parameterIndex) throws SQLException;

576

}

577

```

578

579

**Usage Examples:**

580

581

```java

582

import java.sql.Connection;

583

import java.sql.CallableStatement;

584

import java.sql.Types;

585

import java.sql.SQLException;

586

587

// Example 1: Call function with return value

588

public class FunctionCallExample {

589

public static void callFunction(Connection conn) throws SQLException {

590

// PostgreSQL function: CREATE FUNCTION get_user_count() RETURNS integer

591

String sql = "{ ? = call get_user_count() }";

592

593

try (CallableStatement cstmt = conn.prepareCall(sql)) {

594

// Register OUT parameter for return value

595

cstmt.registerOutParameter(1, Types.INTEGER);

596

597

// Execute

598

cstmt.execute();

599

600

// Get return value

601

int count = cstmt.getInt(1);

602

System.out.println("User count: " + count);

603

}

604

}

605

}

606

607

// Example 2: Call function with IN and OUT parameters

608

public class InOutParametersExample {

609

public static void callWithParameters(Connection conn) throws SQLException {

610

// Function: CREATE FUNCTION calculate_discount(price numeric, OUT discount numeric)

611

String sql = "{ call calculate_discount(?, ?) }";

612

613

try (CallableStatement cstmt = conn.prepareCall(sql)) {

614

// Set IN parameter

615

cstmt.setBigDecimal(1, new java.math.BigDecimal("100.00"));

616

617

// Register OUT parameter

618

cstmt.registerOutParameter(2, Types.NUMERIC);

619

620

// Execute

621

cstmt.execute();

622

623

// Get OUT parameter

624

java.math.BigDecimal discount = cstmt.getBigDecimal(2);

625

System.out.println("Discount: " + discount);

626

}

627

}

628

}

629

630

// Example 3: Call function returning composite type

631

public class CompositeReturnExample {

632

public static void callReturningComposite(Connection conn) throws SQLException {

633

// Function returning user record

634

String sql = "SELECT * FROM get_user_by_id(?)";

635

636

try (CallableStatement cstmt = conn.prepareCall(sql)) {

637

cstmt.setInt(1, 123);

638

639

try (ResultSet rs = cstmt.executeQuery()) {

640

if (rs.next()) {

641

String name = rs.getString("name");

642

String email = rs.getString("email");

643

System.out.println(name + ": " + email);

644

}

645

}

646

}

647

}

648

}

649

650

// Example 4: Call procedure (PostgreSQL 11+)

651

public class ProcedureCallExample {

652

public static void callProcedure(Connection conn) throws SQLException {

653

// Procedure: CREATE PROCEDURE transfer_funds(from_id int, to_id int, amount numeric)

654

String sql = "{ call transfer_funds(?, ?, ?) }";

655

656

try (CallableStatement cstmt = conn.prepareCall(sql)) {

657

cstmt.setInt(1, 100); // from_id

658

cstmt.setInt(2, 200); // to_id

659

cstmt.setBigDecimal(3, new java.math.BigDecimal("50.00")); // amount

660

661

cstmt.execute();

662

System.out.println("Funds transferred");

663

}

664

}

665

}

666

```

667

668

### Query Execution Modes

669

670

PostgreSQL JDBC driver supports different query execution protocols.

671

672

```java { .api }

673

package org.postgresql.jdbc;

674

675

/**

676

* Query execution mode options.

677

* Controls which PostgreSQL protocol is used for query execution.

678

*

679

* Note: Invalid mode values default to EXTENDED.

680

*/

681

public enum PreferQueryMode {

682

/**

683

* Use simple query protocol (text-only).

684

* Sends queries as plain text, receives results as text.

685

* Does not support binary transfer or certain features.

686

*/

687

SIMPLE,

688

689

/**

690

* Always use extended query protocol.

691

* Supports binary transfer, prepared statements, and all features.

692

* Slightly more overhead than simple protocol.

693

* This is the default fallback for invalid/unknown mode values.

694

*/

695

EXTENDED,

696

697

/**

698

* Use extended protocol only for prepared statements.

699

* Simple statements use simple protocol.

700

* Default mode providing good balance of features and performance.

701

*/

702

EXTENDED_FOR_PREPARED,

703

704

/**

705

* Extended protocol with aggressive caching.

706

* Caches all statement plans, even for simple statements.

707

* Provides best performance for repeated queries.

708

*/

709

EXTENDED_CACHE_EVERYTHING;

710

711

/**

712

* Returns the string value of this mode for use in connection properties.

713

*

714

* @return String value (e.g., "simple", "extended", "extendedForPrepared", "extendedCacheEverything")

715

*/

716

public String value();

717

718

/**

719

* Parses a string mode value and returns the corresponding enum constant.

720

*

721

* @param mode String mode value

722

* @return PreferQueryMode enum constant, or EXTENDED if mode is invalid/unknown

723

*/

724

public static PreferQueryMode of(String mode);

725

}

726

```

727

728

**Usage Example:**

729

730

```java

731

import org.postgresql.PGProperty;

732

import java.sql.Connection;

733

import java.sql.DriverManager;

734

import java.util.Properties;

735

736

public class QueryModeExample {

737

public static Connection getConnectionWithMode(String mode) throws SQLException {

738

Properties props = new Properties();

739

props.setProperty("user", "postgres");

740

props.setProperty("password", "secret");

741

props.setProperty("preferQueryMode", mode); // simple, extended, etc.

742

743

return DriverManager.getConnection("jdbc:postgresql://localhost/mydb", props);

744

}

745

}

746

```

747

748

### Statement Performance Tips

749

750

**Best Practices:**

751

752

1. **Use PreparedStatement for repeated queries**

753

```java

754

// Good: PreparedStatement with parameter

755

PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?");

756

pstmt.setInt(1, userId);

757

758

// Bad: Statement with concatenation (SQL injection risk!)

759

Statement stmt = conn.createStatement();

760

stmt.executeQuery("SELECT * FROM users WHERE id = " + userId);

761

```

762

763

2. **Use batch operations for bulk inserts**

764

```java

765

PreparedStatement pstmt = conn.prepareStatement("INSERT INTO logs (msg) VALUES (?)");

766

for (String msg : messages) {

767

pstmt.setString(1, msg);

768

pstmt.addBatch();

769

}

770

pstmt.executeBatch(); // Much faster than individual executes

771

```

772

773

3. **Configure prepare threshold appropriately**

774

```java

775

// For frequently executed statements, prepare immediately

776

PreparedStatement pstmt = conn.prepareStatement(sql);

777

((PGStatement) pstmt).setPrepareThreshold(0);

778

779

// For rarely executed statements, never prepare

780

((PGStatement) pstmt).setPrepareThreshold(-1);

781

```

782

783

4. **Set fetch size for large result sets**

784

```java

785

Statement stmt = conn.createStatement();

786

stmt.setFetchSize(100); // Fetch 100 rows at a time

787

ResultSet rs = stmt.executeQuery("SELECT * FROM large_table");

788

```

789

790

5. **Reuse PreparedStatement objects**

791

```java

792

// Good: Reuse prepared statement

793

PreparedStatement pstmt = conn.prepareStatement(sql);

794

for (User user : users) {

795

pstmt.setString(1, user.getName());

796

pstmt.executeUpdate();

797

pstmt.clearParameters();

798

}

799

pstmt.close();

800

```

801