JDBC学习笔记
JDBC基本用法
JDBC Java DataBase Connectivity Java语言连接数据库
本质 sun公司制定的一套接口
面向接口编程 降低耦合度,提高可扩展能力
JDBC编程六步
注册驱动 | 即将连接的是哪一个数据库型号 |
---|---|
获取连接 | 表示JVM进程和数据库通道打开,属于进程间的通信,重量级 |
获取数据库操作对象 | 专门执行sql语句的对象 |
执行SQL语句 | DQL DML … |
处理查询结果集 | 只有上一步是selece时,才执行这一步 |
释放资源 | 使用完一定要关闭资源。这数据进程间的通信,时间久会有问题 |
注册驱动
try{
DriverManager.registerDriver(new come.mysql.jdbc.Driver());
}
catch(SQLException e){
e.printStackTrace();
}
//推荐使用这种方法
try{
String driver = "com.mysql.jdbc.Driver";
Class.forName(driver);
}
catch(CLassNotFoundException e){
e.printStackTrace();
}
获取连接
String url = "jdbc:mysql://127.0.0.1:3306/database";
// jdbc:mysql://ip:端口/数据库名
String user = "root";
String password = "password";
Connection conn = DriverManager.getConnection(url,user,password);
获取数据库操作对象
Statement stmt = conn.createStatement();
执行SQL语句
//sql语句不用写分号;
String sql = "insert into ... values...";
int count = stmt.executeUpdate(sql);
System.out.println(count == 1 ? "保存成功" : "保存失败");
释放资源
finally{
//从小到大进行关闭
try{
if(stmt != null){
stmt.close;
}
}
catch(SQLException e){
e.printStackTrace();
}
try{
if(conn != null){
conn.close;
}
}
catch(SQLException e){
e.printStackTrace();
}
}
增删改总执行步骤
Connection conn = null;
Statement stmt = null;
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://127.0.0.1:3306/database";
String user = "root";
String password = "password";
try{
//加载驱动
Class.forName(driver);
//获取连接
conn = DriverManager.getConnection(url,user,password);
//获取数据库操作对象
stmt = conn.createStatement();
//执行SQL语句
String sql = "insert into ... values...";
int count = stmt.executeUpdate(sql);
System.out.println(count == 1 ? "保存成功" : "保存失败");
}
catch(SQLException e){
e.printStackTrace();
}
catch(ClassNotFoundException e){
e.printStackTrace();
}
finally{
//从小到大进行关闭
try{
if(stmt != null){
stmt.close;
}
}
catch(SQLException e){
e.printStackTrace();
}
try{
if(conn != null){
conn.close;
}
}
catch(SQLException e){
e.printStackTrace();
}
}
使用配置文件进行操作
--jdbc.proerpties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/database
user=root
password=password
Connection conn = null;
Statement stmt = null;
ResourceBundle bundle= ResourceBundle.getBundle("jdbc");
String driver = bundle.getString("driver");
String url = bundle.getString("url");
String user = bundle.getString("user");
String password = bundle.getString("password");
查询
ResultSet rs = null;
String sql = "select empno,ename,sal fron emp";
//执行DQL的方法 executeQuery
rs = stmt.executeQuery(sql);
//处理查询结果集 next 下一行 每一列从1-n
//遍历结果集
while(rs.next()){
int empno = rs.getInt("empno");
String ename = rs.getStirng("ename");
double sal = rs.getDouble("sal");
}
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
String driver = bundle.getString("driver");
String url = bundle.getString("url");
String user = bundle.getString("user");
String password = bundle.getString("password");
try{
Class.forName(driver);
conn = DriverManager.getConnection(url,user,password);
stmt = conn.createStatement();
String sql = "select empno,ename,sal fron emp";
//执行DQL的方法 executeQuery
rs = stmt.executeQuery(sql);
//处理查询结果集 next 下一行 每一列从1-n
//遍历结果集
while(rs.next()){
int empno = rs.getInt("empno");
String ename = rs.getStirng("ename");
double sal = rs.getDouble("sal");
}
}
catch(SQLException e){
e.printStackTrace();
}
catch(ClassNotFoundException e){
e.printStackTrace();
}
finally{
try{
if(rs != null) rs.close;
}
catch(SQLException e){
e.printStackTrace();
}
try{
if(stmt != null) stmt.close;
}
catch(SQLException e){
e.printStackTrace();
}
try{
if(conn != null) conn.close;
}
catch(SQLException e){
e.printStackTrace();
}
}
数据库模型的设计工具 PowerDesigner,一款强大的数据库模型设计工具
SQL 注入
安全隐患 在用户输入信息时,输入了sql语句,导致sql语句被修改
例子
//原SQL语句
String username;
String password;
String sql = "select * from emp where username = '"+username+"' and password = '"+password+"'";
//用户输入
username = qianzi
password = qianzi' or '1' = '1
//拼接的sql为
String sql = "select * from emp where username = 'qianzi' and password = 'qianzi' or '1' = '1'";
//导致password无论是什么都会登录成功
根本原因 用户输入的信息被拼接到SQL语句中,并且被编译,导致原sql语句被扭曲了
解决方案 只要用户提供的信息不参与编译过程,即使用户提供的信息含有sql关键字
使用 PreparedStatement 替换 Statemenet PreparedStatement 会对sql进行预编译,只能传值进去
//获取预编译的数据库操作对象
PreparedStatement ps;
//其中一个?表示一个占位符,?不需要''括起来
String sql = "select * from emp where username = ? and password = ?";
//预编译
ps = conn.prepareStatement(sql);
//设置占位符
ps.setString(1,username);
ps.setString(2,password);
//获取结果集
rs = ps.executeQuery();
PreparedStatement执行效率比Statement高
先编译,然后每次只需要执行,不需要再编译
PreparedStatement在编译时进行安全检查
PreparerStatement使用情况较多,一般情况下不使用Statement
当项目开发时需要sql注入的时候,才使用Statement,一般情况下不需要用户输入内容
JDBC 事务
JDBC事务 JDBC默认自动提交事务
在业务中,要使得几个sql语句同时成功或失败,需要使用事务
修改手动提交
conn.setAutoCommit(false);
提交和回滚
conn.commit(); //提交
conn.rollback(); //回滚
格式
try{
conn.setAutoCommit(false); //开启事务
...
conn.commit(); //提交事务
}
catch(Exception e){
if(conn != null){
try{
conn.rollback;
}
catch(SQLException e){
e.printStackTrace();
}
}
}
JDBC 工具类
publice class DBUtil{
//工具类中的方法是私有的
private DBUtil() { }
//静态代码块在类加载时执行一次
static{
try{
Class.forName("com.mysql.jdbc.Driver");
}
catch(ClassNotFoundException e){
e.printStackTrace();
}
}
//获取数据库连接对象
public static Connection getConnection() throws SQLException{
return DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/database","root","password");
}
//关闭资源
public static void close(Connection conn,Statement ps,ResultSet rs){
try{
if(rs != null) rs.close;
}
catch(SQLException e){
e.printStackTrace();
}
try{
if(stmt != null) stmt.close;
}
catch(SQLException e){
e.printStackTrace();
}
try{
if(conn != null) conn.close;
}
catch(SQLException e){
e.printStackTrace();
}
}
}
SQL 行级锁
行级锁 悲观锁,for update,在sql语句最后加。为了不让其他事务操作sql找出来的数据。事务必须排队执行,不允许并发
乐观锁 事务可以并发,并对数据设置版本号