第十八章:JDBC
作者:java_wxid
连接数据库的方式:
第一种方式:ODBC:开放数据库连接是微软公司开放服务结构中有关数据库的一个组成部分,是数据库访问接口标准。ODBC是基于C语言实现的。提供了语言和数据库进行交互的一致性的接口,便于语言和数据库通信以及语言对数据库的各种操作。
第二种方式:JDBC(本章重点)
在Java中,数据库存取技术可分为如下几类:
第一种:JDBC直接访问数据库
第二种 :JDO技术(Java Data Object)
第三种:第三方O/R工具,如Hibernate, Mybatis 等
JDBC是java访问数据库的基石,JDO, Hibernate等只是更好的封装了JDBC。
什么是JDBC?
JDBC: Java Data Base Connectivity(java数据库连接)
它是sun公司提供的一套java应用程序访问数据库的技术或规范。是一种用于执行SQL语句的Java API,它统一和规范了应用程序与数据库的连接、执行SQL语句,并到得到返回结果等各类操作,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。
JDBC的好处
1、减少了开发程序员的压力,不用去记多套API
2、提高了维护性
如何使用?
第一步:导入jar包:
1.使用JDBC操作数据库,需要导入JDBC的驱动包:mysql-connector-java-5.1.36-bin.jar。
2.在项目下新建libs文件夹,将jar包复制到libs文件夹下面
注意:如果是Dynamic Web Project(动态的web项目)话,则是把驱动jar放到WebContent(有的开发工具叫WebRoot)目录中的WEB-INF目录中的lib目录下即可
3.右键–>Build Path–>Add to Build Path,这时,我们可以在项目的引用包中看到我们引用的jar包.
第二步:Java应用程序访问数据库的过程:
①装载数据库驱动程序;
MySQL的驱动下载地址:http://dev.mysql.com/downloads/
加载驱动:把驱动类加载到内存
注册驱动:把驱动类的对象交给DriverManager管理,用于后面创建连接等使用。
第一种方式:DriverManager.registerDriver(new Driver());//不建议使用
第二种方式: Class.forName(“com.mysql.jdbc.Driver”);//通过反射,加载与注册驱动类,解耦合(不直接依赖)
②通过JDBC建立数据库连接;
③访问数据库,执行SQL语句;
④断开数据库连接。
java.sql包
javax.sql包
此类用于演示JDBC使用的简单步骤
/**
* 此类用于演示JDBC使用的简单步骤
* 前提:
* ①需要将mysql-connector-java-5.1.37-bin.jar复制到项目的libs目录
* ②右击mysql-connector-java-5.1.37-bin,Build Path——Add To buildPath
*
*/
public class TestConnection {
public static void main(String[] args) throws SQLException {
// 1.加载驱动(准备工作)
DriverManager.registerDriver(new Driver());
// 2.获取连接
/*
* 参数1:url
* 格式:jdbc:mysql://主机名:端口号/库名
* 参数2:用户名
* 参数3:密码
*/
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/customersDB", "root", "root");
// 3.执行增删改查★
//①获取执行sql语句的命令对象
Statement statement = connection.createStatement();
//②执行sql语句
int update = statement.executeUpdate("delete from customers where id=2");
//③处理结果
System.out.println(update>0?"success":"failure");
// 4.关闭连接
statement.close();
connection.close();
}
}
PreparedStatement的使用
/**
* 一、向customers表中插入数据,效果如下:
请输入编号:55
请输入姓名:上官红
请输入邮箱:[email protected]
请输入生日(要求按xxxx-xx-xx格式):1988-11-11
插入成功!
*/
public class TestPreparedStatementByUtils {
//增删改
@Test
public void test1() throws Exception {
Scanner input = new Scanner(System.in);
System.out.println("请输入编号:");
int id = input.nextInt();
System.out.println("请输入姓名:");
String name = input.next();
System.out.println("请输入邮箱:");
String email = input.next();
System.out.println("请输入生日:");
String birth = input.next();
//-----------------------------连接数据库的步骤-----------------
//1.获取连接
Connection connection = JDBCUtils.getConnection();
//2、执行插入
PreparedStatement statement = connection.prepareStatement("insert into customers values(?,?,?,?,null)");
statement.setInt(1, id);
statement.setString(2, name);
statement.setString(3, email);
statement.setString(4, birth);
int update = statement.executeUpdate();
System.out.println(update>0?"插入成功":"插入失败");
//3.关闭
JDBCUtils.close(null, statement, connection);
}
//查询
@Test
public void test2() throws Exception {
// 请输入编号:1
// ---------------------------------------------------------------------------------
// 编号 姓名 邮箱 生日
// 1 汪峰 [email protected] 2010-2-2
Scanner input = new Scanner(System.in);
System.out.println("请输入编号:");
int id = input.nextInt();
//-----------------------------连接数据库的步骤-----------------
//1.获取连接
Connection connection = JDBCUtils.getConnection();
//2、执行查询
PreparedStatement statement = connection.prepareStatement(
"select id,name,email,birth from customers where id = ?");
statement.setInt(1, id);
ResultSet set = statement.executeQuery();
if(set.next()) {
String name = set.getString(2);
String email = set.getString(3);
String birth = set.getString(4);
System.out.println(id+"\t"+name+"\t"+email+"\t"+birth);
}
//3.关闭
JDBCUtils.close(set, statement, connection);
}
}
此类用于演示批处理和PreparedStatement与Statement之间的效率问题
/**
* 此类用于演示批处理
* 情况1:多条sql语句的批量执行【较少使用】
* Statement+批处理:提高了执行的效率,并没有减少编译的次数
* 情况2:一条sql语句的批量传参【较多使用】
* PreparedStatement+批处理:减少了执行的次数,也减少了编译的次数,大大提高效率
* 相关API:
* addBatch()
* executeBatch()
* clearBatch()
* 注意:
* ①需要在url添加reWriteBatchedStatement = true
* 驱动类使用的版本:5.1.37、5.1.36但不能使用5.1.7(不支持批处理)
* ②插入时,使用values,而不是value!
*案例:添加50000条管理员记录
*/
public class TestBatch {
//没有使用批处理
@Test
public void testNoBatch() throws Exception {
//1.获取连接
Connection connection = JDBCUtils.getConnection();
//2.执行插入
PreparedStatement statement = connection.prepareStatement("insert into admin values(?,?,?)");
for(int i=1;i<=50000;i++) {
statement.setInt(1, i);
statement.setString(2, "john"+i);
statement.setString(3, "0000");
statement.executeUpdate();
}
//3.关闭
JDBCUtils.close(null, statement, connection);
}
//使用批处理
@Test
public void testUseBatch() throws Exception {
//1.获取连接
Connection connection = JDBCUtils.getConnection();
//2.执行插入
PreparedStatement statement = connection.prepareStatement("insert into admin values(?,?,?)");
for(int i=1;i<=50000;i++) {
statement.setInt(1, i);
statement.setString(2, "john"+i);
statement.setString(3, "0000");
//添加到批处理包(放到框中)
statement.addBatch();
if(i%1000==0) {
statement.executeBatch();//执行批处理包的sql(将框中的苹果们运到了楼上)
statement.clearBatch();//清空批处理包的sql(卸货)
}
}
//3.关闭
JDBCUtils.close(null, statement, connection);
}
}
Blob类型数据的读写
/**
* 此类用于演示Blob类型数据的读写
* 注意:只能使用PreparedStatement实现Blob类型的读写,不能使用Statement
* 相关API:
* setBlob(占位符索引,InputStream)
* InputStream is =getBinaryStream(列索引)
*/
public class TestBlob {
//测试Blob类型数据的写入:修改小苍的照片为指定照片
@Test
public void test1() throws Exception {
//1.获取连接
Connection connection = JDBCUtils.getConnection();
//2.执行修改
PreparedStatement statement = connection.prepareStatement("update customers set photo = ? where name = ?");
statement.setBlob(1, new FileInputStream("E:\\beauty\\cang.jpg"));//★
statement.setString(2, "小苍");
int update = statement.executeUpdate();
System.out.println(update>0?"插入成功":"插入失败");
//3.关闭
JDBCUtils.close(null, statement, connection);
}
//测试Blob类型数据的读取:将小苍的图片读取到项目的根目录下
@Test
public void test2() throws Exception {
//1.获取连接
Connection connection = JDBCUtils.getConnection();
//2.执行查询
PreparedStatement statement = connection.prepareStatement("select photo from customers where name = ?");
statement.setString(1, "小苍");
ResultSet set = statement.executeQuery();
if(set.next()) {
// Blob blob = set.getBlob(1);
// InputStream binaryStream = blob.getBinaryStream();
InputStream inputStream = set.getBinaryStream(1);
FileOutputStream fos = new FileOutputStream("src\\beauty.jpg");
//边读边写:复制图片
byte[] b = new byte[1024];
int len;
while((len=inputStream.read(b))!=-1) {
fos.write(b, 0, len);
}
fos.close();
inputStream.close();
}
//3.关闭连接资源
JDBCUtils.close(set, statement, connection);
}
}
##JDBC常用的API
DriverManager驱动管理类
registDriver 加载驱动【不建议使用】
getConnection获取连接【后期往往通过数据库连接池获取】
Connection连接接口
createStatement()获取命令对象
prepareStatement(sql)获取预编译命令对象
close
Statement命令对象接口
executeUpdate(sql)执行增删改语句,返回受影响的行数
executeQuery(sql)执行查询语句,返回ResultSet对象
execute(sql)执行任何sql语句,返回是否是结果集
close
PreparedStatement预编译命令对象
executeUpdate()执行增删改语句,返回受影响的行数
executeQuery()执行查询语句,返回ResultSet对象
execute()执行任何sql语句,返回是否是结果集
setXX(占位符的索引,占位符的值):设置对应占位符的值为XX类型的变量(索引从1开始)
setObject(占位符索引,占位符的值):设置对应占位符的值为Object类型的变量
close
ResultSet结果集接口
next()下移一行,指向当前行,返回指向的新行是否有数据
getXX(columnIndex|columnName)根据列索引或列名获取XX类型的值
getObject(columnIndex|columnName)根据列索引或列名获取Object类型的值
previous()上移一行,指向当前行,返回指向的新行是否有数据
close
##德鲁伊连接池的使用
###连接池的好处
1、提高效率
2、提高重用性
3、采用一套统一的管理机制,减少数据库崩溃问题
###数据库连接池的使用
javax.sql包下的DataSource是一个数据库连接池接口。一些开源组织对它进行了实现。
多种开源的数据库连接池:C3P0,DBCP,Druid,BoneCP,Proxool
###德鲁伊使用方式一:
//创建一个数据库连接池
DruidDataSource dds = new DruidDataSource();
//设置连接参数
dds.setUrl("jdbc:mysql://localhost:3306/customersDB");
dds.setUsername("root");
dds.setPassword("root");
dds.setDriverClassName("com.mysql.jdbc.Driver");
//设置池子中的初始化连接数
dds.setInitialSize(5);
//设置池子中的最大连接数
dds.setMaxActive(10);
//设置池子中的最小连接数
dds.setMinIdle(5);
//获取连接
Connection connection = dds.getConnection();
System.out.println("connected!");
###德鲁伊使用方式二:
Properties properties = new Properties(); properties.load(this.getClass().getClassLoader().getResourceAsStream("druid.properties"));
//1、获取连接池
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
//2、获取连接
Connection connection = dataSource.getConnection();
System.out.println(connection);
//3.关闭连接
connection.close();
druid.properties
#key=value
driverClassName=com.mysql.jdbc.Driver
#url=jdbc:mysql://localhost:3306/bookstore?rewriteBatchedStatements=true
url=jdbc:mysql://localhost:3306/customersDB
username=root
password=root
initialSize=10
minIdle=5
maxActive=20
maxWait=5000
事务
@Test
public void testTransaction() {
//1.获取连接
Connection connection = null;
//事务使用步骤二:编写事务的语句
//2.执行增删改查
PreparedStatement statement = null;
try {
connection = JDBCUtils.getConnection();
//事务使用步骤一:开启事务
connection.setAutoCommit(false);//取消了事务的自动提交+开启事务
statement = connection.prepareStatement("update account set balance = ? where username = ?");
statement.setDouble(1, 995);
statement.setString(2, "冯绍峰");
statement.executeUpdate();
int i=1/0;
//操作2:赵丽颖的钱多5块
statement.setDouble(1, 1005);
statement.setString(2, "赵丽颖");
statement.executeUpdate();
//事务使用步骤三:结束事务
connection.commit();//如果执行到该处,说明上面操作没有异常,则可以正常提交事务
} catch (SQLException e) {
try {
connection.rollback();//如果执行到该处,说明try块操作有异常,则需要回滚!
} catch (SQLException e1) {
e1.printStackTrace();
}
}
finally {
//3.关闭连接
try {
JDBCUtils.close(null, statement, connection);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
批处理
//使用批处理
@Test
public void testUseBatch() throws Exception {
//1.获取连接
Connection connection = JDBCUtils.getConnection();
//2.执行插入
PreparedStatement statement = connection.prepareStatement("insert into admin values(?,?,?)");
for(int i=1;i<=50000;i++) {
statement.setInt(1, i);
statement.setString(2, "john"+i);
statement.setString(3, "0000");
//添加到批处理包(放到框中)
statement.addBatch();
if(i%1000==0) {
statement.executeBatch();//执行批处理包的sql(将框中的苹果们运到了楼上)
statement.clearBatch();//清空批处理包的sql(卸货)
}
}
//3.关闭
JDBCUtils.close(null, statement, connection);
}
自己动手封装一个BasicDao
/**
* 自己动手封装一个BasicDao
* 功能:
* 1、通用的增删改
* 针对于任何表的增删改语句
* 2、通用的查询单条(返回的是一行信息)
* 针对于任何表的任何查询单条的记录
* 返回类型:T 对象
* orm思想:一个表映射成一个类,一条记录映射成一个对象,一个字段映射成一个属性
* 参数:Class clazz,String sql,Object...objects
* 3、通用的查询多条(返回的是多行信息)
* 针对于 任何表的任何查询多条的记录
* 返回类型:List<T>
* 参数:Class clazz,String sql,Object...objects
*/
public class BasicDaoBySelf {
/**
* 功能:针对于任何表的查询多条
* @param clazz
* @param sql
* @param objects
* @return List<T>
*/
public <T> List<T> queryMulti(Class<T> clazz,String sql,Object...objects){
Connection connection = null;
PreparedStatement statement = null;
ResultSet set = null;
try {
connection = JDBCUtils.getConnection();
statement = connection.prepareStatement(sql);
for (int i = 0; i < objects.length; i++) {
statement.setObject(i+1, objects[i]);
}
set = statement.executeQuery();
ResultSetMetaData metaData = set.getMetaData();
List<T> list = new ArrayList<>();//集合
int columnCount = metaData.getColumnCount();
while(set.next()) {
T t = clazz.newInstance();
for(int i=1;i<=columnCount;i++) {
//获取属性名(列名)
String fieldName = metaData.getColumnLabel(i);
//获取属性值(列的值)
Object value = set.getObject(i);
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(t, value);
}
list.add(t);
}
return list;
}catch(Exception e) {
throw new RuntimeException(e);
}finally {
JDBCUtils.close(set, statement, connection);
}
}
/**
* 功能:执行任何表的查询单条记录的sql语句
* @param clazz 表针对的类的Class对象
* @param sql 待执行的sql
* @param objects 占位符
* @return T 类型的对象(表中的一条记录以对象的形式返回)
* @throws Exception
*/
public<T> T querySingle(Class<T> clazz,String sql,Object...objects) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet set = null;
try {
//1.获取连接
connection = JDBCUtils.getConnection();
//2.执行查询
statement = connection.prepareStatement(sql);
for (int i = 0; i < objects.length; i++) {
statement.setObject(i+1, objects[i]);
}
set = statement.executeQuery();
/*
* 一、元数据结果集的使用
* ResultSet:保存结果集的数据
* 元数据结果集:解剖ResultSet的结构
* 二、反射的使用
* 封装对象:
* 正常的方式:
* ①调用无参构造创建对象
* 类名 对象名 = new 类名();
* ②为对象的各个属性赋值
* 对象名.属性名=值;
* 反射的方式:
* 创建对象:
* T t= clazz.newInstance();
* 为属性赋值:
* Field field = t.getDecalaredField(属性名);
* field.setAccessible(true);
* field.set(t,value);
* 三、泛型的使用
*/
//获取元数据结果集
ResultSetMetaData metaData = set.getMetaData();
//结果集的列数
int columnCount = metaData.getColumnCount();
if(set.next()) {
T t= clazz.newInstance();
for(int i=1;i<=columnCount;i++) {//遍历列数
String columnLabel = metaData.getColumnLabel(i);//根据列索引获取列名或别名(属性名)
Object value = set.getObject(i);//拿到该列的值(各个属性的值)
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t,value);
}
return t;
}
return null;
} catch (Exception e) {
throw new RuntimeException(e);
}
finally {
JDBCUtils.close(set, statement, connection);
}
}
/**
* 功能:通用的增删改语句
* @param sql 待执行的sql,里面可能有占位符
* @param objects 占位符的值
* @return 受影响的行数
* @throws SQLException
* @throws Exception
*/
public int update(String sql,Object...objects) {
//1.获取连接
Connection connection= null;
PreparedStatement statement = null;
try {
connection = JDBCUtils.getConnection();
//2.执行sql
statement = connection.prepareStatement(sql);
for(int i=0;i<objects.length;i++) {
statement.setObject(i+1, objects[i]);
}
int update = statement.executeUpdate();
return update;
} catch (Exception e) {
throw new RuntimeException(e);//将编译异常转换成运行异常
}
finally {
//3.关闭
JDBCUtils.close(null, statement, connection);
}
}
}
00000000000000000000000000000000000000000000000000000000000000000000
使用JDBCUTils工具类自己写一个增删改,查询单条,多条记录,查询单个值的通用方法
/**
* 此类用于演示DBUTils的使用
* QueryRunner
* update
* query
* ResultSetHandler
* BeanHandler
* BeanListHandler
* ScalarHandler
*/
public class BasicDaoByUtils<T> {
QueryRunner qr = new QueryRunner();
/**
* 通用的增删改
* @param sql
* @param objects
* @return
*/
public int update(String sql,Object...objects) {
Connection connection = null;
try {
connection = JDBCUtils.getConnection();
return qr.update(connection, sql, objects);
} catch (Exception e) {
throw new RuntimeException(e);
}
finally {
JDBCUtils.close(null, null, connection);
}
}
/**
* 功能:查询单条
* @param clazz
* @param sql
* @param objects
* @return
*/
public T querySingle(Class<T> clazz,String sql,Object...objects) {
Connection connection = null;
try {
connection = JDBCUtils.getConnection();
return qr.query(connection, sql, new BeanHandler<T>(clazz),objects);
} catch (Exception e) {
throw new RuntimeException(e);
}
finally {
JDBCUtils.close(null, null, connection);
}
}
/**
* 功能:查询多条
* @param clazz
* @param sql
* @param objects
* @return
*/
public List<T> queryMulti(Class<T> clazz,String sql,Object...objects) {
Connection connection = null;
try {
connection = JDBCUtils.getConnection();
return qr.query(connection, sql, new BeanListHandler<T>(clazz),objects);
} catch (Exception e) {
throw new RuntimeException(e);
}
finally {
JDBCUtils.close(null, null, connection);
}
}
/**
* 功能:查询单个值
* @param sql
* @param objects
* @return
*/
public Object scalar(String sql,Object...objects) {
Connection connection = null;
try {
connection = JDBCUtils.getConnection();
return qr.query(connection, sql, new ScalarHandler(),objects);
} catch (Exception e) {
throw new RuntimeException(e);
}
finally {
JDBCUtils.close(null, null, connection);
}
}
}
JDBCUtils工具类
/**
* jdbc工具类
*/
public class JDBCUtils {
static DataSource dataSource;
static {
try {
Properties properties = new Properties();
properties.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
dataSource = DruidDataSourceFactory.createDataSource(properties);
}catch (Exception e) {
e.printStackTrace();
}
}
//使用druid获取连接
public static Connection getConnection() throws Exception {
return dataSource.getConnection();
}
//使用c3p0获取连接
public static Connection getConnection2() throws SQLException {
ComboPooledDataSource cpds = new ComboPooledDataSource("hello");
return cpds.getConnection();
}
//释放连接资源
public static void close(ResultSet set,Statement statement,Connection connection){
try {
if(set!=null)
set.close();
if(statement!=null)
statement.close();
if(connection!=null)
connection.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
测试工具类的使用情况
/**
* 此类用于测试工具类的使用
*/
public class TestDBUtils {
@Test
public void test1() {
BasicDaoByUtils<Admin> bd = new BasicDaoByUtils<>();
int update = bd.update("update admin set username = ? where id =?", "小花",2);
System.out.println(update>0?"success":"failure");
}
@Test
public void test2() {
BasicDaoByUtils<Admin> bd = new BasicDaoByUtils<>();
// Admin querySingle = bd.querySingle(Admin.class, "select * from Admin where id=?", 2);//Admin自己新建的实体类
// System.out.println(querySingle);
List<Admin> list = bd.queryMulti(Admin.class, "select * from Admin where id<?", 10);
for (Admin admin : list) {
System.out.println(admin);
}
Object scalar = bd.scalar("select count(*) from admin");
System.out.println(scalar);
}
}
00000000000000000000000000000000000000000000000000000000000000000000
JDBC相关的API
一、Connection接口:
1.createStatement():创建数据库连接
2.prepareStatement(String sql):创建预处理语句
3.prepareCall(String sql):创建可调用语句
4.getAutoCommit():获取自动提交的模式
5.setAutoCommit():设置自动提交的模式
6.commit():提交所执行的SQL语句
7.rollback():回滚所执行的SQL语句
8.getMetaData():获取一个DatabaseMetaData对象,该对象包含了有关数据库的基本信息
9.close():关闭数据库连接
10.isClose():判断数据库连接是否超时或被显示关闭
二、Statement接口:
1.execute(String sql):执行SQL语句,如果返回值是结果集则为true,否则为false
2.executeQuery(String sql):执行SQL语句,返回值为ResultSet
3.executeUpdate(String sql):执行SQL语句,返回值为所影响的行数
4.addBatch(String sql):向当前Statement对象的命令列表中添加新的批处理SQL语句
5.clearBatch():清空当前Statement对象的命令列表
6.executeBatch():执行当前Statement对象的批处理语句,返回值为每个语句所影响的函数数组
7.getConnection():返回创建了该Statement对象的Connection对象
8.getQueryTimeout():获取等待处理结果的时间
9.setQueryTimeout():设置等待处理结果的时间
三、ResultSet接口:
1.first()/beforeFirst():将游标移动到ResultSet中第一条记录(的前面)
2.last()/afterLast():将游标移动到ResultSet中最后一条记录(的后面)
3.absolute(int column):将游标移动到相对于第一行的指定行,负数则为相对于最后一条记录
4.relative(int rows):将游标移动到相对于当前行的第几行,正为向下,负为向上
5.next():将游标下移一行
6.previous():将游标上移一行
7.insertRow():向当前ResultSet和数据库中被插入行处插入一条记录
8.deleteRow():将当前ResultSet中的当前行和数据库中对应的记录删除
9.updateRow():用当前ResultSet中已更新的记录更新数据库中对应的记录
10.cancelUpdate():取消当前对ResultSet和数据库中所做的操作
11.findColumn(String columnName):返回当前ResultSet中与指定列名对应的索引
12.getRow():返回ResultSet中的当前行号
13.refreshRow():更新当前ResultSet中的所有记录
14.getMetaData():返回描述ResultSet的ResultSetMetaData对象
15.isAfterLast(): 是否到了结尾
16.isBeforeFirst(): 是否到了开头
17.isFirst():是否第一条记录
18.isLast(): 是否最后一条记录
19.wasNull():检查列值是否为NULL值,如果列的类型为基本类型,且数据库中的值为0,那么这项检查就很重要。由于数据库NULL也返回0,所以0值和数据库的NULL不能区分。如果列的类型为对象,可以简单地将返回值与null比较
20.close():关闭当前ResultSet
四、ResultSetMetaData接口:
1.getColumnCount():返回ResultSet中列的数目
2.getColumnName():返回列在数据库中的名称
3.getColumnType():返回列的SQL类型
4.isReadOnly():表示该数据项是否为只读值
5.isNullable():表示该列是否可以存储NULL
上一篇: JDBC章节总结
下一篇: JDBC事务隔离级别 几种?(5种)