or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-annotations.mdindex.mdsecurity-annotations.mdsql-annotations.md

sql-annotations.mddocs/

0

# SQL Annotations

1

2

Jakarta SQL Annotations provide declarative database DataSource configuration and JNDI registration. These annotations enable database setup without external configuration files, allowing developers to define DataSource properties directly in code.

3

4

## Capabilities

5

6

### DataSource Configuration

7

8

Annotations for defining and configuring database connections with JNDI registration.

9

10

#### @DataSourceDefinition

11

12

Defines a container DataSource to be registered with JNDI. Configures all DataSource properties including connection details, pool settings, and transaction behavior.

13

14

**Important**: DataSource properties should not be specified more than once. If the URL contains properties that are also specified using annotation elements, the precedence order is undefined and implementation-specific. If properties are specified in both the properties array and as annotation elements, the annotation element value takes precedence.

15

16

```java { .api }

17

/**

18

* Defines a container DataSource for JNDI registration.

19

* Configures database connection and pooling properties.

20

*/

21

@Target(TYPE)

22

@Retention(RUNTIME)

23

@Repeatable(DataSourceDefinitions.class)

24

public @interface DataSourceDefinition {

25

/**

26

* JNDI name by which the data source will be registered (required).

27

*/

28

String name();

29

30

/**

31

* DataSource implementation class name (required).

32

* Must implement DataSource, XADataSource, or ConnectionPoolDataSource.

33

*/

34

String className();

35

36

/**

37

* Description of the data source.

38

*/

39

String description() default "";

40

41

/**

42

* JDBC URL for the database connection.

43

*/

44

String url() default "";

45

46

/**

47

* User name for database authentication.

48

*/

49

String user() default "";

50

51

/**

52

* Password for database authentication.

53

*/

54

String password() default "";

55

56

/**

57

* Database name on the server.

58

*/

59

String databaseName() default "";

60

61

/**

62

* Port number where database server is listening.

63

*/

64

int portNumber() default -1;

65

66

/**

67

* Database server name.

68

*/

69

String serverName() default "localhost";

70

71

/**

72

* Transaction isolation level.

73

* Values from Connection interface: TRANSACTION_READ_UNCOMMITTED,

74

* TRANSACTION_READ_COMMITTED, TRANSACTION_REPEATABLE_READ, TRANSACTION_SERIALIZABLE.

75

*/

76

int isolationLevel() default -1;

77

78

/**

79

* Whether connections participate in transactions.

80

*/

81

boolean transactional() default true;

82

83

/**

84

* Initial number of connections in the pool.

85

*/

86

int initialPoolSize() default -1;

87

88

/**

89

* Maximum number of concurrent connections in the pool.

90

*/

91

int maxPoolSize() default -1;

92

93

/**

94

* Minimum number of connections in the pool.

95

*/

96

int minPoolSize() default -1;

97

98

/**

99

* Maximum time (seconds) unused connection remains in pool.

100

*/

101

int maxIdleTime() default -1;

102

103

/**

104

* Total number of statements the connection pool should keep open.

105

*/

106

int maxStatements() default -1;

107

108

/**

109

* Vendor-specific properties in "propertyName=propertyValue" format.

110

*/

111

String[] properties() default {};

112

113

/**

114

* Maximum time (seconds) to wait while connecting to database.

115

*/

116

int loginTimeout() default 0;

117

}

118

```

119

120

**Usage Examples:**

121

122

```java

123

import jakarta.annotation.sql.DataSourceDefinition;

124

import java.sql.Connection;

125

126

// Basic MySQL DataSource

127

@DataSourceDefinition(

128

name = "java:global/MyAppDataSource",

129

className = "com.mysql.cj.jdbc.MysqlDataSource",

130

url = "jdbc:mysql://localhost:3306/myapp",

131

user = "appuser",

132

password = "secret123"

133

)

134

public class DatabaseConfig {

135

}

136

137

// Advanced PostgreSQL configuration with connection pooling

138

@DataSourceDefinition(

139

name = "java:app/PostgresDS",

140

className = "org.postgresql.ds.PGPoolingDataSource",

141

serverName = "db.example.com",

142

portNumber = 5432,

143

databaseName = "production",

144

user = "produser",

145

password = "prodpass",

146

description = "Production PostgreSQL database",

147

isolationLevel = Connection.TRANSACTION_READ_COMMITTED,

148

transactional = true,

149

initialPoolSize = 5,

150

maxPoolSize = 20,

151

minPoolSize = 2,

152

maxIdleTime = 300,

153

maxStatements = 100,

154

loginTimeout = 10,

155

properties = {

156

"ssl=true",

157

"sslmode=require",

158

"prepareThreshold=3"

159

}

160

)

161

public class ProductionDatabaseConfig {

162

}

163

164

// H2 in-memory database for testing

165

@DataSourceDefinition(

166

name = "java:comp/env/TestDB",

167

className = "org.h2.jdbcx.JdbcDataSource",

168

url = "jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1",

169

user = "sa",

170

password = "",

171

description = "In-memory H2 database for testing"

172

)

173

public class TestConfiguration {

174

}

175

176

// Oracle with XA support

177

@DataSourceDefinition(

178

name = "java:global/OracleXADS",

179

className = "oracle.jdbc.xa.client.OracleXADataSource",

180

url = "jdbc:oracle:thin:@oracle.example.com:1521:ORCL",

181

user = "appuser",

182

password = "oraclepass",

183

transactional = true,

184

isolationLevel = Connection.TRANSACTION_SERIALIZABLE,

185

properties = {

186

"oracle.jdbc.implicitStatementCacheSize=20",

187

"oracle.jdbc.fanEnabled=false"

188

}

189

)

190

public class OracleConfig {

191

}

192

```

193

194

#### @DataSourceDefinitions

195

196

Container annotation for multiple @DataSourceDefinition declarations. Allows defining multiple DataSources on a single class.

197

198

```java { .api }

199

/**

200

* Container for multiple @DataSourceDefinition annotations.

201

* Allows multiple DataSource definitions on a single class.

202

*/

203

@Target(TYPE)

204

@Retention(RUNTIME)

205

public @interface DataSourceDefinitions {

206

/**

207

* Array of DataSourceDefinition annotations.

208

*/

209

DataSourceDefinition[] value();

210

}

211

```

212

213

**Usage Examples:**

214

215

```java

216

import jakarta.annotation.sql.DataSourceDefinitions;

217

import jakarta.annotation.sql.DataSourceDefinition;

218

219

// Multiple DataSources for microservice architecture

220

@DataSourceDefinitions({

221

@DataSourceDefinition(

222

name = "java:global/UserDB",

223

className = "com.mysql.cj.jdbc.MysqlDataSource",

224

url = "jdbc:mysql://userdb:3306/users",

225

user = "userservice",

226

password = "userpass",

227

description = "User management database"

228

),

229

@DataSourceDefinition(

230

name = "java:global/OrderDB",

231

className = "org.postgresql.ds.PGSimpleDataSource",

232

url = "jdbc:postgresql://orderdb:5432/orders",

233

user = "orderservice",

234

password = "orderpass",

235

description = "Order processing database"

236

),

237

@DataSourceDefinition(

238

name = "java:global/InventoryDB",

239

className = "com.mysql.cj.jdbc.MysqlDataSource",

240

url = "jdbc:mysql://inventorydb:3306/inventory",

241

user = "inventoryservice",

242

password = "invpass",

243

description = "Inventory tracking database"

244

)

245

})

246

public class MultiDatabaseApplication {

247

}

248

249

// Read/Write split configuration

250

@DataSourceDefinitions({

251

@DataSourceDefinition(

252

name = "java:comp/env/ReadOnlyDB",

253

className = "com.mysql.cj.jdbc.MysqlDataSource",

254

url = "jdbc:mysql://slave.db.example.com:3306/myapp",

255

user = "readonly",

256

password = "readpass",

257

description = "Read-only slave database",

258

maxPoolSize = 10,

259

properties = {"readOnly=true"}

260

),

261

@DataSourceDefinition(

262

name = "java:comp/env/ReadWriteDB",

263

className = "com.mysql.cj.jdbc.MysqlDataSource",

264

url = "jdbc:mysql://master.db.example.com:3306/myapp",

265

user = "readwrite",

266

password = "writepass",

267

description = "Read-write master database",

268

maxPoolSize = 5,

269

transactional = true

270

)

271

})

272

public class ReadWriteSplitConfig {

273

}

274

275

// Development vs Production configurations

276

@DataSourceDefinitions({

277

@DataSourceDefinition(

278

name = "java:global/DevDB",

279

className = "org.h2.jdbcx.JdbcDataSource",

280

url = "jdbc:h2:~/devdb",

281

user = "dev",

282

password = "dev",

283

description = "Development H2 database"

284

),

285

@DataSourceDefinition(

286

name = "java:global/ProdDB",

287

className = "org.postgresql.ds.PGPoolingDataSource",

288

serverName = "prod.db.company.com",

289

portNumber = 5432,

290

databaseName = "production",

291

user = "produser",

292

password = "prodpass",

293

description = "Production PostgreSQL database",

294

initialPoolSize = 10,

295

maxPoolSize = 50,

296

minPoolSize = 5

297

)

298

})

299

public class EnvironmentDatabaseConfig {

300

}

301

```

302

303

## DataSource Integration Patterns

304

305

### Using Defined DataSources

306

307

```java

308

import jakarta.annotation.Resource;

309

import jakarta.annotation.sql.DataSourceDefinition;

310

import javax.sql.DataSource;

311

312

@DataSourceDefinition(

313

name = "java:app/MyDS",

314

className = "com.mysql.cj.jdbc.MysqlDataSource",

315

url = "jdbc:mysql://localhost:3306/mydb",

316

user = "user",

317

password = "pass"

318

)

319

public class DatabaseService {

320

321

// Injecting the defined DataSource

322

@Resource(lookup = "java:app/MyDS")

323

private DataSource dataSource;

324

325

public List<User> getUsers() {

326

try (Connection conn = dataSource.getConnection();

327

PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users")) {

328

329

ResultSet rs = stmt.executeQuery();

330

List<User> users = new ArrayList<>();

331

while (rs.next()) {

332

users.add(mapToUser(rs));

333

}

334

return users;

335

} catch (SQLException e) {

336

throw new RuntimeException("Database error", e);

337

}

338

}

339

}

340

```

341

342

### Connection Pool Configuration

343

344

```java

345

// High-performance production setup

346

@DataSourceDefinition(

347

name = "java:global/HighPerformanceDB",

348

className = "com.zaxxer.hikari.HikariDataSource",

349

url = "jdbc:postgresql://db.example.com:5432/app",

350

user = "appuser",

351

password = "apppass",

352

initialPoolSize = 10, // Start with 10 connections

353

maxPoolSize = 50, // Max 50 concurrent connections

354

minPoolSize = 5, // Keep minimum 5 connections

355

maxIdleTime = 600, // 10 minutes idle timeout

356

maxStatements = 250, // Statement cache size

357

loginTimeout = 5, // 5 second connection timeout

358

properties = {

359

"maximumPoolSize=50",

360

"minimumIdle=5",

361

"connectionTimeout=5000",

362

"idleTimeout=600000",

363

"maxLifetime=1800000", // 30 minutes max connection lifetime

364

"leakDetectionThreshold=60000" // 1 minute leak detection

365

}

366

)

367

public class HighPerformanceConfig {

368

}

369

```

370

371

### Multi-Tenant Database Configuration

372

373

```java

374

@DataSourceDefinitions({

375

@DataSourceDefinition(

376

name = "java:global/TenantA_DB",

377

className = "com.mysql.cj.jdbc.MysqlDataSource",

378

url = "jdbc:mysql://tenant-a.db.example.com:3306/tenant_a",

379

user = "tenant_a_user",

380

password = "tenant_a_pass",

381

description = "Tenant A dedicated database"

382

),

383

@DataSourceDefinition(

384

name = "java:global/TenantB_DB",

385

className = "com.mysql.cj.jdbc.MysqlDataSource",

386

url = "jdbc:mysql://tenant-b.db.example.com:3306/tenant_b",

387

user = "tenant_b_user",

388

password = "tenant_b_pass",

389

description = "Tenant B dedicated database"

390

),

391

@DataSourceDefinition(

392

name = "java:global/SharedDB",

393

className = "com.mysql.cj.jdbc.MysqlDataSource",

394

url = "jdbc:mysql://shared.db.example.com:3306/shared",

395

user = "shared_user",

396

password = "shared_pass",

397

description = "Shared tenant database"

398

)

399

})

400

public class MultiTenantConfiguration {

401

}

402

```