Of course! This is a very common and important topic when working with Java applications that connect to an Oracle database. The NUMBER data type in Oracle is highly flexible, and mapping it correctly to Java types is crucial for data integrity and application performance.

Here’s a comprehensive guide covering everything from the basics to best practices.
Understanding the Oracle NUMBER Data Type
First, it's essential to understand what Oracle's NUMBER type is. It's a highly flexible numeric data type that can store zero, positive, and negative numbers with a precision of up to 38 digits.
The general syntax is:
NUMBER(precision, scale)
- Precision: The total number of digits. It can range from 1 to 38. If you omit it, the precision is up to 38 digits.
- Scale: The number of digits to the right of the decimal point. It can range from -84 to 127.
Here are the most common use cases:

| Declaration | Description | Example Value |
|---|---|---|
NUMBER |
A floating-point number with up to 38 digits of precision. | 12345678901234567890123456789012345678 |
NUMBER(p) |
A fixed-point integer with p digits. |
NUMBER(10) can store 1234567890 |
NUMBER(p, s) |
A fixed-point number with p total digits and s after the decimal. |
NUMBER(5, 2) can store 45 |
NUMBER(*, s) |
A floating-point number with a fixed scale s. |
NUMBER(*, 2) can store 12 |
NUMBER(38) |
A 38-digit integer. Often used for large IDs or counts. | 99999999999999999999999999999999999999 |
The Standard JDBC Way: java.math.BigDecimal
When you use standard JDBC (Java Database Connectivity), the Oracle JDBC driver maps the NUMBER type to java.math.BigDecimal.
This is the most important rule to remember:
Oracle
NUMBER⇔ Javajava.math.BigDecimal
Why BigDecimal?
- Precision: Unlike
floatordouble,BigDecimalcan represent numbers with exact precision, which is critical for financial data, currency, and any number where rounding errors are unacceptable. - Scale: It can handle the scale specified in the
NUMBER(p, s)type correctly.
Example using JDBC (The Old Way)
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class JdbcNumberExample {
public static void main(String[] args) {
String url = "jdbc:oracle:thin:@localhost:1521:ORCLCDB";
String user = "your_username";
String password = "your_password";
// SQL with a NUMBER column
String sql = "SELECT product_id, price, quantity_in_stock FROM products";
try (Connection conn = DriverManager.getConnection(url, user, password);
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
// Get the ID (likely NUMBER(10))
int id = rs.getInt("product_id"); // Works for small integers
// Get the price (likely NUMBER(10, 2))
BigDecimal price = rs.getBigDecimal("price"); // BEST PRACTICE
// Get the quantity (likely NUMBER(10))
long quantity = rs.getLong("quantity_in_stock"); // Works for large integers
System.out.println("ID: " + id + ", Price: " + price + ", Qty: " + quantity);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Using JPA / Hibernate (The Modern ORM Way)
When you use an Object-Relational Mapping (ORM) framework like JPA with Hibernate, you have more flexibility in choosing your Java types. The ORM will handle the conversion to BigDecimal internally.

Here are the common Java types you can map to an Oracle NUMBER column in your JPA entity.
Scenario 1: Exact Numbers (Currency, Financial Data)
This is the most important case. You should always use BigDecimal for monetary values.
import javax.persistence.*;
import java.math.BigDecimal;
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// Best practice for currency or precise decimal numbers
@Column(name = "price", precision = 10, scale = 2)
private BigDecimal price;
// Getters and Setters...
}
Scenario 2: Integers (No Decimal Part)
If your NUMBER column is guaranteed to be an integer (e.g., NUMBER(10)), you can use the appropriate Java integer type. This is more convenient and type-safe.
| Oracle Type | Java Type | Notes |
|---|---|---|
NUMBER(2) |
byte |
For small numbers (-128 to 127) |
NUMBER(5) |
short |
For small to medium numbers |
NUMBER(9) |
int |
Most common for IDs, flags, etc. |
NUMBER(18) |
long |
For large numbers that fit in a long |
NUMBER(19) or larger |
java.math.BigInteger |
For very large integers |
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// Using int for a status flag (e.g., 0=PENDING, 1=SHIPPED)
private int status;
// Using long for a large order number
private long orderNumber;
// Getters and Setters...
}
Scenario 3: Approximate Numbers (Scientific Data)
If the precision is not critical and the number can have a very wide range (e.g., scientific notation), you can use double. Be aware of potential rounding errors.
@Entity
public class SensorReading {
@Id
private Long id;
// Using double for a measurement where precision is not 100% critical
private double temperature;
// Getters and Setters...
}
Using jOOQ (The Modern SQL DSL Way)
jOOQ is a popular library for writing type-safe SQL queries in Java. It provides excellent support for Oracle's NUMBER type.
jOOQ strongly encourages the use of BigDecimal for all NUMBER types to maintain precision.
import org.jooq.DSLContext;
import org.jooq.impl.DSL;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DriverManager;
import static org.jooq.impl.DSL.name; // For table/column names
public class JooqNumberExample {
public static void main(String[] args) {
String url = "jdbc:oracle:thin:@localhost:1521:ORCLCDB";
String user = "your_username";
String password = "your_password";
try (Connection conn = DriverManager.getConnection(url, user, password)) {
DSLContext dsl = DSL.using(conn);
// jOOQ maps NUMBER to BigDecimal by default
BigDecimal price = dsl.select(DSL.field("price", BigDecimal.class))
.from(name("products"))
.where(name("product_id").eq(101))
.fetchOne()
.value1();
System.out.println("The price is: " + price);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Summary and Best Practices
Oracle NUMBER Column |
Recommended Java Type | Why? |
|---|---|---|
NUMBER(p, s) (with s > 0) |
java.math.BigDecimal |
The only correct choice. Guarantees precision and scale, essential for financial data. |
NUMBER(p) (integer, fits in int) |
int |
Convenient, type-safe, and avoids the overhead of BigDecimal. Use for IDs, flags, counts. |
NUMBER(p) (integer, fits in long) |
long |
Same as above, for larger integer values. |
NUMBER(p) (very large integer) |
java.math.BigInteger |
For integers that exceed the capacity of a long. |
NUMBER (floating point, approximate) |
double |
Use with caution. Acceptable for scientific data where minor precision loss is acceptable. Avoid for money. |
Quick Decision Flowchart
Is the column an integer? (no decimal part)
|
+-- YES --> Does it fit in an `int` (up to ~2 billion)?
| |
| +-- YES --> Use `int`.
| |
| +-- NO --> Does it fit in a `long`?
| |
| +-- YES --> Use `long`.
| |
| +-- NO --> Use `BigInteger`.
|
+-- NO (it has a decimal part) --> Use `BigDecimal`.
By following these guidelines, you'll ensure that your Java application handles Oracle numeric data accurately and efficiently.
