目录
什么是JDBC
JDBC编程六部曲:
一、java.sql.DriverManger【是sql包的类】
二、com.mysql .jdbc.Driver【mysql实现的接口(Driver)类 】
三、java.sql.Connection【接口】
四、java.sql.Statement;【抽象接口。用来处理必须要使用拼接才能执行的SQL语句】
五-四、java.sql.preparedStatement【Statement的子接口】
六、java.util.ResultSet【处理查询结果集(select)】
八、释放资源
代码演示
SQL注入问题
悲观锁和乐观锁的概念
什么是JDBC
-
JDBC其实就是SUN公司制定的一套接口(interface)【在
java.sql.*中】
-
因为每一个数据的底层实现原理不一样。所以都是一堆接口。【降低耦合度】
-
java程序员都在面向JDBC接口写代码
-
数据库厂家负责编写这些实现类,(一堆xxx.class 文件/mysql驱动jar包)【这些class文件需要去各大数据库的官网下载。注意:
jdbc驱动的jar包一定要和mysql的版本兼容】
-
为什么要面向接口编程:解耦合,降低程序的耦合度。提高程序的扩展力。【多态就是经典的面向抽象编程】
-
注意:JDBC中所有下标从 1 开始
JDBC编程六部曲:
-
注册驱动【告诉java程序,即将要连接的是哪一个品牌的数据库】
-
获取连接【表示jvm的进程和数据库进程之间的通道 】
-
获取数据库对象【专门执行SQL语句的/数据库操作对象】
-
执行SQL语句【DML DQL】
-
处理查询结果集【只有执行select语句的时候,才有第五步处理查询结果】
-
释放资源【java和数据库之间属于进程间的通信】
一、java.sql.DriverManger【是sql包的类】
常用方法:
-
注册驱动方法
-
static void
registerDrver(Driver driver);【需要一个Driver对象作为参数,抛出的异常:SQLException】
-
第二种方式【这种方式常用】
-
在Driver中有一个静态代码块。【静态代码块在类加载的时候会执行】
-
Class.
forName("com.mysql .jdbc.Driver");【不需要接收返回值。因为我们只要类加载这个行为动作】
-
这种方式常用的原因是参数是一个字符串,可以写在
一个属性配置文件中。【使用资源绑定器】
-
获取连接
-
static Connection
getConnection(String
url,String
user,String
password);【抛出的异常:SQLException。】
-
URL/统一资源定位符:"
jdbc:mysql://服务器ip地址 : 3306/资源名"【
协议 ip:端口号/资源名、资源名我们这里一般写数据库的名称】
-
user:用户名
-
password:用户密码
二、com.mysql .jdbc.Driver【mysql实现的接口(Driver)类 】
-
这个实现类中有一个静态代码块。里面执行了注册驱动方法。
-
三、java.sql.Connection【接口】
常用方法
-
获得数据库操作对象
-
Statement createStatement( );【抛出的异常:SQLException。因为返回值是Statement对象。所以不常用(后面有讲)】
-
PreparedStatement
prepareStatement(String SQL);【
常用】
-
需要一个SQL语句作为参数,返回一个预编译的数据库操作对象
-
并且sql语句中的动态拼接对象都变成"
?"【
一个
?表示一个占位符,?不需要单引号括起来,一个?将来接收一个值】
-
这个语句会发送SQL语句框给DBMS,然后DBMS进行SQL语句的预先编译。
-
void setAutoCommit(boolean autoCommit);【用来修改提交机制。默认自动提交】
-
autoCommit:参数为true表示启用自动提交机制。false为禁用
-
void commit( );【手动提交数据/事务】
-
void rollback( );【数据/事务回滚。一般使用在catch中(如果不为空执行)】
-
就是数据库里做修改后( update ,insert , delete)
未 commit 之前 使用 rollback 可以
恢复数据到修改之前。
-
这句代码,假设在执行第一句执行完后,数据库服务器故障,抛出异常了,第二句就没有执行。这时候数据库的情况就是:id为1的name更新了,id为2的name没有更新。假设业务逻辑不能容忍这种只执行一半的情况,那么就应该rollback,把id为1的name恢复到一切执行之前的情况。
-
如果业务逻辑可以容忍这种只执行一半SQL的行为,那就不需要rollback。
-
数据库事务控制的精髓就一句话:对于一堆sql语句来说,要么都执行,
要么都不执行。其中“要么都不执行”的部分,就是用rollback实现的
注:
JDBC中只要
执行任意一条DML语句,就提交一次
【有自动提交机制,一般需要修改为手动提交】
四、java.sql.Statement;【抽象接口。用来处理必须要使用拼接才能执行的SQL语句】
-
编译一次就只能执行一次
-
不做类型的安全检查
常用方法【
执行SQL语句】:
-
int
executeUpdate(String SQL );【可能执行insert、update、delete语句
增删改,或者不返回任何内容的语句(DML)】
-
注:返回值是执行改指定语句后
影响数据库中的记录条数
-
ResultSet executeQuery( );【执行给定的SQL语句返回一个ResultSet对象】
五-四、java.sql.preparedStatement【Statement的子接口】
-
预编译的sql对象
-
编译一次可执行n次【效率高,因为mysql的底层原因】、
-
编译时会做类型的安全检查【
编译时会多类型传参进行检查。方法要求只能是String类型实参】
-
用来解决SQL
注入问题
常用方法:
-
void setString(int x,String str);【因为已经预编译了,所以在这里面如果传了SQL语句也不会执行/编译,只编译一次】
-
x表示给第几个占位符传值【下标从1开始】
-
str表示传的值是什么。【主要看自己的SQL语句,它会自动给str加上单引号】
-
注:因为是先预编译了,所以一定要先给占位符传值,然后再执行返回查询结果集方法
-
void setInt
(int n,int value
);【根据占位符n传指定值给占位符。有多个类似方法。支持所有基本类型和引用数据类型。会查阅文档就行。这里就不赘述了】
-
执行SQL语句
-
ResultSet
executeQuery
( );【执行SQL语句并返回查询结果集,不需要参数】
-
int executeUpdate( );【执行SQL语句并且返回影响数据的行数】
六、java.util.ResultSet【处理查询结果集(select)】
常用方法【这个接口中有很多方法,记得查阅文档】
-
boolean next( );【从当前光标(指针)指向
下一行,初始时光标不指向任何元素】
-
String getString(int columnIndex
/String str);【不管mysql数据表中存储的是什么数据,取出来的都会变成String】
-
int :根据参数的值拿当前行的指定列值【所有的列下标
从1开始
】
-
String:str表示是列标签。通过列标签
去
拿当前行指定列的值,列标签不存在则报错【常用】
-
int/short/
double…
getint/short/
double(int n
/String str
);【通过其他指定方法取指定类型的值】
-
ResultSetMetaDate getMetaDate( );【获取所有的列名,封装在返回值对象中】
-
void last( );【光标/指针指向最后一行】
-
int getRow( );【获取当前所在的行数,通过这两个方法可以
得到查询结果集一共有多少行】
七、
ResultSetMetaDate 【查询结果处理集封装的具体信息】
常用方法:
-
int getColumnCount( );【返回一共有多少列。注意在JDBC中下标都是从1开始】
-
String getColumnName(int n);【根据下标n拿去指定
列标签名】
八、释放资源
-
为了保证资源一定被释放,建议在finally预计块中关闭资源
-
并且遵循从小到大依次关闭【最先出来的最大】
-
关闭的方法(close)也有异常需要处理。
注:对于这固定的八步,可以自己给一个工具类。其中驱动只需要执行一次,可以写在工具类的静态代码块中(驱动只需要一次,但是可能有多个连接)。
-
注册驱动【告诉java程序,即将要连接的是哪一个品牌的数据库】
-
获取连接【表示jvm的进程和数据库进程之间的通道 】
-
获取数据库对象【专门执行SQL语句的/数据库操作对象】
-
执行SQL语句【DML DQL】
-
处理查询结果集【只有执行select语句的时候,才有第五步处理查询结果】
-
释放资源【java和数据库之间属于进程间的通信】
一、java.sql.DriverManger【是sql包的类】
常用方法:
-
注册驱动方法
-
static void
registerDrver(Driver driver);【需要一个Driver对象作为参数,抛出的异常:SQLException】
-
第二种方式【这种方式常用】
-
在Driver中有一个静态代码块。【静态代码块在类加载的时候会执行】
-
Class.
forName("com.mysql .jdbc.Driver");【不需要接收返回值。因为我们只要类加载这个行为动作】
-
这种方式常用的原因是参数是一个字符串,可以写在
一个属性配置文件中。【使用资源绑定器】
-
获取连接
-
static Connection
getConnection(String
url,String
user,String
password);【抛出的异常:SQLException。】
-
URL/统一资源定位符:"
jdbc:mysql://服务器ip地址 : 3306/资源名"【
协议 ip:端口号/资源名、资源名我们这里一般写数据库的名称】
-
user:用户名
-
password:用户密码
二、com.mysql .jdbc.Driver【mysql实现的接口(Driver)类 】
-
这个实现类中有一个静态代码块。里面执行了注册驱动方法。
-
三、java.sql.Connection【接口】
常用方法
-
获得数据库操作对象
-
Statement createStatement( );【抛出的异常:SQLException。因为返回值是Statement对象。所以不常用(后面有讲)】
-
PreparedStatement
prepareStatement(String SQL);【
常用】
-
需要一个SQL语句作为参数,返回一个预编译的数据库操作对象
-
并且sql语句中的动态拼接对象都变成"
?"【
一个
?表示一个占位符,?不需要单引号括起来,一个?将来接收一个值】
-
这个语句会发送SQL语句框给DBMS,然后DBMS进行SQL语句的预先编译。
-
void setAutoCommit(boolean autoCommit);【用来修改提交机制。默认自动提交】
-
autoCommit:参数为true表示启用自动提交机制。false为禁用
-
void commit( );【手动提交数据/事务】
-
void rollback( );【数据/事务回滚。一般使用在catch中(如果不为空执行)】
-
就是数据库里做修改后( update ,insert , delete)
未 commit 之前 使用 rollback 可以
恢复数据到修改之前。
-
这句代码,假设在执行第一句执行完后,数据库服务器故障,抛出异常了,第二句就没有执行。这时候数据库的情况就是:id为1的name更新了,id为2的name没有更新。假设业务逻辑不能容忍这种只执行一半的情况,那么就应该rollback,把id为1的name恢复到一切执行之前的情况。
-
如果业务逻辑可以容忍这种只执行一半SQL的行为,那就不需要rollback。
-
数据库事务控制的精髓就一句话:对于一堆sql语句来说,要么都执行,
要么都不执行。其中“要么都不执行”的部分,就是用rollback实现的
注:
JDBC中只要
执行任意一条DML语句,就提交一次
【有自动提交机制,一般需要修改为手动提交】
四、java.sql.Statement;【抽象接口。用来处理必须要使用拼接才能执行的SQL语句】
-
编译一次就只能执行一次
-
不做类型的安全检查
常用方法【
执行SQL语句】:
-
int
executeUpdate(String SQL );【可能执行insert、update、delete语句
增删改,或者不返回任何内容的语句(DML)】
-
注:返回值是执行改指定语句后
影响数据库中的记录条数
-
ResultSet executeQuery( );【执行给定的SQL语句返回一个ResultSet对象】
五-四、java.sql.preparedStatement【Statement的子接口】
-
预编译的sql对象
-
编译一次可执行n次【效率高,因为mysql的底层原因】、
-
编译时会做类型的安全检查【
编译时会多类型传参进行检查。方法要求只能是String类型实参】
-
用来解决SQL
注入问题
常用方法:
-
void setString(int x,String str);【因为已经预编译了,所以在这里面如果传了SQL语句也不会执行/编译,只编译一次】
-
x表示给第几个占位符传值【下标从1开始】
-
str表示传的值是什么。【主要看自己的SQL语句,它会自动给str加上单引号】
-
注:因为是先预编译了,所以一定要先给占位符传值,然后再执行返回查询结果集方法
-
void setInt
(int n,int value
);【根据占位符n传指定值给占位符。有多个类似方法。支持所有基本类型和引用数据类型。会查阅文档就行。这里就不赘述了】
-
执行SQL语句
-
ResultSet
executeQuery
( );【执行SQL语句并返回查询结果集,不需要参数】
-
int executeUpdate( );【执行SQL语句并且返回影响数据的行数】
六、java.util.ResultSet【处理查询结果集(select)】
常用方法【这个接口中有很多方法,记得查阅文档】
-
boolean next( );【从当前光标(指针)指向
下一行,初始时光标不指向任何元素】
-
String getString(int columnIndex
/String str);【不管mysql数据表中存储的是什么数据,取出来的都会变成String】
-
int :根据参数的值拿当前行的指定列值【所有的列下标
从1开始
】
-
String:str表示是列标签。通过列标签
去
拿当前行指定列的值,列标签不存在则报错【常用】
-
int/short/
double…
getint/short/
double(int n
/String str
);【通过其他指定方法取指定类型的值】
-
ResultSetMetaDate getMetaDate( );【获取所有的列名,封装在返回值对象中】
-
void last( );【光标/指针指向最后一行】
-
int getRow( );【获取当前所在的行数,通过这两个方法可以
得到查询结果集一共有多少行】
七、
ResultSetMetaDate 【查询结果处理集封装的具体信息】
常用方法:
-
int getColumnCount( );【返回一共有多少列。注意在JDBC中下标都是从1开始】
-
String getColumnName(int n);【根据下标n拿去指定
列标签名】
八、释放资源
-
为了保证资源一定被释放,建议在finally预计块中关闭资源
-
并且遵循从小到大依次关闭【最先出来的最大】
-
关闭的方法(close)也有异常需要处理。
注:对于这固定的八步,可以自己给一个工具类。其中驱动只需要执行一次,可以写在工具类的静态代码块中(驱动只需要一次,但是可能有多个连接)。
- static void registerDrver(Driver driver);【需要一个Driver对象作为参数,抛出的异常:SQLException】
-
第二种方式【这种方式常用】
-
在Driver中有一个静态代码块。【静态代码块在类加载的时候会执行】
- Class. forName("com.mysql .jdbc.Driver");【不需要接收返回值。因为我们只要类加载这个行为动作】
- 这种方式常用的原因是参数是一个字符串,可以写在 一个属性配置文件中。【使用资源绑定器】
-
在Driver中有一个静态代码块。【静态代码块在类加载的时候会执行】
-
static Connection
getConnection(String
url,String
user,String
password);【抛出的异常:SQLException。】
- URL/统一资源定位符:" jdbc:mysql://服务器ip地址 : 3306/资源名"【 协议 ip:端口号/资源名、资源名我们这里一般写数据库的名称】
- user:用户名
- password:用户密码
- 这个实现类中有一个静态代码块。里面执行了注册驱动方法。
三、java.sql.Connection【接口】
常用方法
-
获得数据库操作对象
-
Statement createStatement( );【抛出的异常:SQLException。因为返回值是Statement对象。所以不常用(后面有讲)】
-
PreparedStatement
prepareStatement(String SQL);【
常用】
-
需要一个SQL语句作为参数,返回一个预编译的数据库操作对象
-
并且sql语句中的动态拼接对象都变成"
?"【
一个
?表示一个占位符,?不需要单引号括起来,一个?将来接收一个值】
-
这个语句会发送SQL语句框给DBMS,然后DBMS进行SQL语句的预先编译。
-
void setAutoCommit(boolean autoCommit);【用来修改提交机制。默认自动提交】
-
autoCommit:参数为true表示启用自动提交机制。false为禁用
-
void commit( );【手动提交数据/事务】
-
void rollback( );【数据/事务回滚。一般使用在catch中(如果不为空执行)】
-
就是数据库里做修改后( update ,insert , delete)
未 commit 之前 使用 rollback 可以
恢复数据到修改之前。
-
这句代码,假设在执行第一句执行完后,数据库服务器故障,抛出异常了,第二句就没有执行。这时候数据库的情况就是:id为1的name更新了,id为2的name没有更新。假设业务逻辑不能容忍这种只执行一半的情况,那么就应该rollback,把id为1的name恢复到一切执行之前的情况。
-
如果业务逻辑可以容忍这种只执行一半SQL的行为,那就不需要rollback。
-
数据库事务控制的精髓就一句话:对于一堆sql语句来说,要么都执行,
要么都不执行。其中“要么都不执行”的部分,就是用rollback实现的
注:
JDBC中只要
执行任意一条DML语句,就提交一次
【有自动提交机制,一般需要修改为手动提交】
四、java.sql.Statement;【抽象接口。用来处理必须要使用拼接才能执行的SQL语句】
-
编译一次就只能执行一次
-
不做类型的安全检查
常用方法【
执行SQL语句】:
-
int
executeUpdate(String SQL );【可能执行insert、update、delete语句
增删改,或者不返回任何内容的语句(DML)】
-
注:返回值是执行改指定语句后
影响数据库中的记录条数
-
ResultSet executeQuery( );【执行给定的SQL语句返回一个ResultSet对象】
五-四、java.sql.preparedStatement【Statement的子接口】
-
预编译的sql对象
-
编译一次可执行n次【效率高,因为mysql的底层原因】、
-
编译时会做类型的安全检查【
编译时会多类型传参进行检查。方法要求只能是String类型实参】
-
用来解决SQL
注入问题
常用方法:
-
void setString(int x,String str);【因为已经预编译了,所以在这里面如果传了SQL语句也不会执行/编译,只编译一次】
-
x表示给第几个占位符传值【下标从1开始】
-
str表示传的值是什么。【主要看自己的SQL语句,它会自动给str加上单引号】
-
注:因为是先预编译了,所以一定要先给占位符传值,然后再执行返回查询结果集方法
-
void setInt
(int n,int value
);【根据占位符n传指定值给占位符。有多个类似方法。支持所有基本类型和引用数据类型。会查阅文档就行。这里就不赘述了】
-
执行SQL语句
-
ResultSet
executeQuery
( );【执行SQL语句并返回查询结果集,不需要参数】
-
int executeUpdate( );【执行SQL语句并且返回影响数据的行数】
六、java.util.ResultSet【处理查询结果集(select)】
常用方法【这个接口中有很多方法,记得查阅文档】
-
boolean next( );【从当前光标(指针)指向
下一行,初始时光标不指向任何元素】
-
String getString(int columnIndex
/String str);【不管mysql数据表中存储的是什么数据,取出来的都会变成String】
-
int :根据参数的值拿当前行的指定列值【所有的列下标
从1开始
】
-
String:str表示是列标签。通过列标签
去
拿当前行指定列的值,列标签不存在则报错【常用】
-
int/short/
double…
getint/short/
double(int n
/String str
);【通过其他指定方法取指定类型的值】
-
ResultSetMetaDate getMetaDate( );【获取所有的列名,封装在返回值对象中】
-
void last( );【光标/指针指向最后一行】
-
int getRow( );【获取当前所在的行数,通过这两个方法可以
得到查询结果集一共有多少行】
七、
ResultSetMetaDate 【查询结果处理集封装的具体信息】
常用方法:
-
int getColumnCount( );【返回一共有多少列。注意在JDBC中下标都是从1开始】
-
String getColumnName(int n);【根据下标n拿去指定
列标签名】
八、释放资源
-
为了保证资源一定被释放,建议在finally预计块中关闭资源
-
并且遵循从小到大依次关闭【最先出来的最大】
-
关闭的方法(close)也有异常需要处理。
注:对于这固定的八步,可以自己给一个工具类。其中驱动只需要执行一次,可以写在工具类的静态代码块中(驱动只需要一次,但是可能有多个连接)。
- Statement createStatement( );【抛出的异常:SQLException。因为返回值是Statement对象。所以不常用(后面有讲)】
-
PreparedStatement
prepareStatement(String SQL);【
常用】
- 需要一个SQL语句作为参数,返回一个预编译的数据库操作对象
- 并且sql语句中的动态拼接对象都变成" ?"【 一个 ?表示一个占位符,?不需要单引号括起来,一个?将来接收一个值】
- 这个语句会发送SQL语句框给DBMS,然后DBMS进行SQL语句的预先编译。
- autoCommit:参数为true表示启用自动提交机制。false为禁用
- 就是数据库里做修改后( update ,insert , delete) 未 commit 之前 使用 rollback 可以 恢复数据到修改之前。
- 这句代码,假设在执行第一句执行完后,数据库服务器故障,抛出异常了,第二句就没有执行。这时候数据库的情况就是:id为1的name更新了,id为2的name没有更新。假设业务逻辑不能容忍这种只执行一半的情况,那么就应该rollback,把id为1的name恢复到一切执行之前的情况。
- 如果业务逻辑可以容忍这种只执行一半SQL的行为,那就不需要rollback。
- 数据库事务控制的精髓就一句话:对于一堆sql语句来说,要么都执行, 要么都不执行。其中“要么都不执行”的部分,就是用rollback实现的
- 编译一次就只能执行一次
- 不做类型的安全检查
-
int
executeUpdate(String SQL );【可能执行insert、update、delete语句
增删改,或者不返回任何内容的语句(DML)】
- 注:返回值是执行改指定语句后 影响数据库中的记录条数
- ResultSet executeQuery( );【执行给定的SQL语句返回一个ResultSet对象】
五-四、java.sql.preparedStatement【Statement的子接口】
-
预编译的sql对象
-
编译一次可执行n次【效率高,因为mysql的底层原因】、
-
编译时会做类型的安全检查【
编译时会多类型传参进行检查。方法要求只能是String类型实参】
-
用来解决SQL
注入问题
常用方法:
-
void setString(int x,String str);【因为已经预编译了,所以在这里面如果传了SQL语句也不会执行/编译,只编译一次】
-
x表示给第几个占位符传值【下标从1开始】
-
str表示传的值是什么。【主要看自己的SQL语句,它会自动给str加上单引号】
-
注:因为是先预编译了,所以一定要先给占位符传值,然后再执行返回查询结果集方法
-
void setInt
(int n,int value
);【根据占位符n传指定值给占位符。有多个类似方法。支持所有基本类型和引用数据类型。会查阅文档就行。这里就不赘述了】
-
执行SQL语句
-
ResultSet
executeQuery
( );【执行SQL语句并返回查询结果集,不需要参数】
-
int executeUpdate( );【执行SQL语句并且返回影响数据的行数】
六、java.util.ResultSet【处理查询结果集(select)】
常用方法【这个接口中有很多方法,记得查阅文档】
-
boolean next( );【从当前光标(指针)指向
下一行,初始时光标不指向任何元素】
-
String getString(int columnIndex
/String str);【不管mysql数据表中存储的是什么数据,取出来的都会变成String】
-
int :根据参数的值拿当前行的指定列值【所有的列下标
从1开始
】
-
String:str表示是列标签。通过列标签
去
拿当前行指定列的值,列标签不存在则报错【常用】
-
int/short/
double…
getint/short/
double(int n
/String str
);【通过其他指定方法取指定类型的值】
-
ResultSetMetaDate getMetaDate( );【获取所有的列名,封装在返回值对象中】
-
void last( );【光标/指针指向最后一行】
-
int getRow( );【获取当前所在的行数,通过这两个方法可以
得到查询结果集一共有多少行】
七、
ResultSetMetaDate 【查询结果处理集封装的具体信息】
常用方法:
-
int getColumnCount( );【返回一共有多少列。注意在JDBC中下标都是从1开始】
-
String getColumnName(int n);【根据下标n拿去指定
列标签名】
八、释放资源
-
为了保证资源一定被释放,建议在finally预计块中关闭资源
-
并且遵循从小到大依次关闭【最先出来的最大】
-
关闭的方法(close)也有异常需要处理。
注:对于这固定的八步,可以自己给一个工具类。其中驱动只需要执行一次,可以写在工具类的静态代码块中(驱动只需要一次,但是可能有多个连接)。
- x表示给第几个占位符传值【下标从1开始】
- str表示传的值是什么。【主要看自己的SQL语句,它会自动给str加上单引号】
- 注:因为是先预编译了,所以一定要先给占位符传值,然后再执行返回查询结果集方法
- ResultSet executeQuery ( );【执行SQL语句并返回查询结果集,不需要参数】
- int executeUpdate( );【执行SQL语句并且返回影响数据的行数】
- boolean next( );【从当前光标(指针)指向 下一行,初始时光标不指向任何元素】
-
String getString(int columnIndex
/String str);【不管mysql数据表中存储的是什么数据,取出来的都会变成String】
- int :根据参数的值拿当前行的指定列值【所有的列下标 从1开始 】
- String:str表示是列标签。通过列标签 去 拿当前行指定列的值,列标签不存在则报错【常用】
- int/short/ double… getint/short/ double(int n /String str );【通过其他指定方法取指定类型的值】
- ResultSetMetaDate getMetaDate( );【获取所有的列名,封装在返回值对象中】
- void last( );【光标/指针指向最后一行】
- int getRow( );【获取当前所在的行数,通过这两个方法可以 得到查询结果集一共有多少行】
- int getColumnCount( );【返回一共有多少列。注意在JDBC中下标都是从1开始】
- String getColumnName(int n);【根据下标n拿去指定 列标签名】
八、释放资源
-
为了保证资源一定被释放,建议在finally预计块中关闭资源
-
并且遵循从小到大依次关闭【最先出来的最大】
-
关闭的方法(close)也有异常需要处理。
注:对于这固定的八步,可以自己给一个工具类。其中驱动只需要执行一次,可以写在工具类的静态代码块中(驱动只需要一次,但是可能有多个连接)。
代码演示
public class Text02 {
public static void main(String[] args) {
Connection ce= null;
Statement st=null;
ResultSet rs=null;
ResultSetMetaData rsm=null;
//这里是一个资源绑定器
ResourceBundle rb=ResourceBundle.getBundle("day01/Text02p");
String className=rb.getString("mysql");
String url=rb.getString("url");
String user=rb.getString("user");
String password=rb.getString("password");
//通过配置文件写入sql语句
String sqlStatements =rb.getString("sqlStatements");
try {
//类加载的方式注册驱动
Class.forName(className);
//获取连接
System.out.println(className);
System.out.println(url);
System.out.println(user);
System.out.println(password);
ce= DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/diyige","root","123456");
// cct=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/diige","root","123456");
//获得处理结果集对象
st=ce.createStatement();
rs= st.executeQuery(sqlStatements);
//通过rs处理查询结果集对象的方法得到所有的列名 格式化select查到的数据
rsm= rs.getMetaData();
int count=rsm.getColumnCount();
String[] arr=new String[count];
for(int i=1;i<=count;i++){
//动态通过列标签拿值
arr[i-1]=rsm.getColumnName(i);
System.out.print(arr[i-1]+"tt");
}
System.out.println();
System.out.println("*****************************************");
while (rs.next()){
for(int i=1;i<=count;i++){
//动态通过列标签拿值
System.out.print(rs.getString(arr[i-1])+"tt");
}
System.out.println();
}
} catch (Exception e) {
e.printStackTrace();
}finally{
//关闭资源
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(st!=null){
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(ce!=null){
try {
ce.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
SQL注入问题
-
这个问题通常是基于在动态拼接SQL语句上的
-
SQL注入是一个安全问题,因为应用程序使用拼接SQL的技术而成为hacker攻击后台的方式。下面就介绍一下3种SQL注入,及解决SQL注入的方法。
-
下面以登录的机制为例,进行SQL注入的讲解。
-
基于 1=1 总为真
-
SELECT * FROM Users WHERe UserId = 105 OR 1=1;
-
黑客只需在输入字段中插入105或1=1,就可以访问数据库中的所有用户名和密码。
-
基于 ""=""总为真
-
SELECt * FROM Users WHERe Name ="" or ""="" AND Pass ="" or ""=""
-
or “”=""总为真(等号左边等于等号右边)
-
基于批处理SQL
-
SELECt * FROM Users WHERe UserId = 105; DROp TABLE Suppliers;
-
删除表Suppliers,很明显对数据库进行破坏,可能造成后台瘫痪。
-
防止SQL注入的解决方法---使用SQL参数
-
txtUserId = getRequestString("UserId");
-
sql = "SELECT * FROM Customers WHERe CustomerId = @0";
-
command = new SqlCommand(sql);
-
command.Parameters.AddWithValue("@0",txtUserID);
-
command.ExecuteReader();
-
如何防止SQL注入
- 这个问题通常是基于在动态拼接SQL语句上的
- SQL注入是一个安全问题,因为应用程序使用拼接SQL的技术而成为hacker攻击后台的方式。下面就介绍一下3种SQL注入,及解决SQL注入的方法。
-
下面以登录的机制为例,进行SQL注入的讲解。
- 基于 1=1 总为真
- SELECT * FROM Users WHERe UserId = 105 OR 1=1;
-
黑客只需在输入字段中插入105或1=1,就可以访问数据库中的所有用户名和密码。
- 基于 ""=""总为真
-
SELECt * FROM Users WHERe Name ="" or ""="" AND Pass ="" or ""=""
- or “”=""总为真(等号左边等于等号右边)
-
基于批处理SQL
- SELECt * FROM Users WHERe UserId = 105; DROp TABLE Suppliers;
- 删除表Suppliers,很明显对数据库进行破坏,可能造成后台瘫痪。
-
防止SQL注入的解决方法---使用SQL参数
- txtUserId = getRequestString("UserId");
- sql = "SELECT * FROM Customers WHERe CustomerId = @0";
- command = new SqlCommand(sql);
- command.Parameters.AddWithValue("@0",txtUserID);
- command.ExecuteReader();
- 如何防止SQL注入
1.永远不要信任用户的输入。对用户的输入进行校验,可以通过正则表达式,或限制长度;对单引号和双"-"进行转换等。
2.永远不要使用动态拼装sql,可以使用参数化的sql或者直接使用存储过程进行数据查询存取。
3.永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。
4.不要把机密信息直接存放,加密或者hash掉密码和敏感的信息。
5.应用的异常信息应该给出尽可能少的提示,最好使用自定义的错误信息对原始错误信息进行包装
6. sql注入的检测方法一般采取辅助软件或网站平台来检测,软件一般采用sql注入检测工具jsky,网站平台就有亿思网站安全平台检测工具。
悲观锁和乐观锁的概念
一、悲观锁/行级锁
-
select * from Student where id=1 for update
-
如果在select后面加了for update ,表示符合规则的每一行数据,在当前事务结束之前。所有人都不能更改这些指定行
-
实际开发:当你在查询表的时候。不希望其他任何人修改就可以使用这个【当前线程会陷入阻塞。等待触发悲观锁的事务结束】
-
事务必须得排队执行。数据锁住了,不允许并发
-
二、乐观锁
-
多线程并发的时候,都可以对指定表的任何数据进行修改
-
支持并发,事务也不需要排队。只不过需要一个同一个版本号



