JDBC
一、JDBC的步骤:
- 创建工程,导入相应数据库对应的jar包
- 注册驱动:
Class.forName("com.mysql.jdbc.Driver");
; - 链接数据库:
Connection conn=DriverManager.getConnection(url,userName,passWord);
- 定义SQL要执行的语句:
String sqlStr="~~~~~~";
- 获取执行SQL语句的对象:
Statement stm = conn.createStatement();
- 执行SQL语句:
stm.executeUpdate(sqlStr);
二、JDBC的API详解
-
DriverManager: 驱动管理类
(1) 注册驱动
(2) 获取数据库链接 -
Connection: 数据库链接对象
获取执行SQL的对象
(1) 普通执行SQL的对象:Statement createStatement();
(2) 预编译SQL中执行SQL的对象, 防止 SQL注入:PreparedStatement prepareStatement(sql);
(3) 执行存储过程的对象:CallableStatement prepareCall(sql);
不常用。管理事务
事务的例子:假如你欠小明500块钱,你需要向小明账户汇款还钱,这时候你通过SQL语句使得你的账号存款会少五百,按理来说,这时候小明也会执行SQL语句,他的账户存款会多500,但是由于有些原因,小明的SQL语句出错了,那么你的账户上的钱已经少了500,而小明账户却没有收到你的汇款。这样显然是不合理的,因此我们便有了事务,事务让你和小明的SQL操作绑定在一起提交,只有你们俩的SQL语句都成功执行,才能修改数据库。如果不成功那么就回滚事务。-
MySQL事务管理
事务名称 关键字 开启事务 BEGIN;或者 START TRANSACTION 提交事务 COMMIT 回滚事务 ROLLBACN MySQL默认自动提交事务
-
JDBC事务管理: Connection接口中定义了3个对应的方法
事务名称 语法 开启事务 setAutoCommit(boolean autoCommit):true为自动提交事务,false 为手动提交事务,即为开启事务 提交事务 commit() 回滚事务 rollback()
-
-
Statement 执行对象类
Statement的作用: 执行SQL语句
执行SQL语句有两类:- 执行DML和DDL的语句:
int executeUpdate(sql);
返回值:DML所影响的行的个数; DDL执行成功也有可能返回0。 - 执行DQL语句:
ResultSet executeQuery((sql);
返回值:ResultSet结果对象。
- 执行DML和DDL的语句:
-
ResultSet 是查询的结果
- 获取结构中的数据
(1)boolean next();
将光标从当前位置向下移动一行,判断当前行是否有效。光标的起始位置在字段定义的那一行。
(2)xxx getXxx(参数)
;获取数据,xxx为数据类型。这个函数有两种重载方式。
注意:第一种重载方式:xxx getXxx(int)
,这个int 传的是表的第几列,起始列为1;
第二种重载方式:xxx getXxx(String)
,这个String就是列的字段名。
- 获取结构中的数据
public class JDBCDemo {
public static void main(String[] args) throws Exception {
//注册驱动;
try {
Class.forName("com.mysql.jdbc.Driver");
}catch (Exception e){
e.printStackTrace();
System.out.print("注册失败");
}
//获取链接,后面这个characterEncoding =ut-8要设置,不然IDEA修改不了mysql数据库中的中文数据
String str="jdbc:mysql://127.0.0.1:3306/db1?useSSL=false&characterEncoding=utf-8";
String userName="root";
String password="123456";
Connection con= DriverManager.getConnection(str,userName,password);
//要执行的SQL语句
String sql1= "update bankCount set money=money-500 where name = \"你\"";//执行你在还钱
String sql2="update bankCount set money=money+500 where name = \"小明\""; //执行小明收钱
String sql3="select *from bankCount;";
//获取执行sql语句的对象
Statement stm=con.createStatement();
try {
//开启事务
con.setAutoCommit(false);
//执行你还钱的SQL
int row11s = stm.executeUpdate(sql1);
System.out.println(row11s);
//执行小明收到你还的钱
int rows22 = stm.executeUpdate(sql2);
System.out.println(rows22);
ResultSet res= stm.executeQuery(sql3);
con.commit();
while (res.next()){
String st=res.getString("name")+" "+res.getInt("money");
System.out.println(st);
}
}catch (Exception throwA){
//进入到catch这个语句块就表明事务出现了异常。这时候就需要回滚
//捕获到异常就会滚
con.rollback();
throwA.printStackTrace();
System.out.println("捕获到异常");
} finally {
//释放资源
stm.close();
con.close();
}
}
}
- PreparedStatement 重点(预编译,解决SQL注入的问题的)
好处:预编译SQL性能更高;且防止SQL注入,将敏感字符进行转义,如单引号。
解释SQL“注入”:入利用sql语句的语法规则,投机取巧的向服务器发起攻击。例如
有一个用户登录表,如图所示:
如果是Statement类对象执行SQL语句
这种情况下,当/*注册和链接数据库操作省略*/ //执行的SQL语句 String name="张三"; //String pwd="zhangsan"; String pwd="'or 'suibian'='suibian";; String sqlStr="select *from student where name='"+name+"'and password='"+pwd+"';"; Statement stm=con.createStatement(); ResultSet res= stm.executeQuery(sqlStr); if(res.next()){ System.out.println("登录成功"); }else { System.out.println("登录失败"); }
pwd="zhangsan"
,这个毫无疑问地,张三这个用户可以正常登录,但是如果当"'or 'suibian'='suibian"
,这时候我们仍然可以登录,且可以得到所有的用户登录信息。为什么会发生这样的事情呢?我们可以打印出stm要执行的sqlStr的语句观察:
这时候我们可以看出:where 后的条件是先得出
name='张三'and password=''
的结果为假,然后再和'suibian'='suibian'
进行或运算。最终的where条件是true,因此,这个就可以理解为SQL注入。
为了解决SQL注入,PreparedStatement 继承 Statement类。其代码如下:
//要执行的SQL语句
String name="张三";
String pwd="zhangsan";
String sqlStr="select *from student where name=? and password=?";
PreparedStatement stm = con.prepareStatement(sqlStr);
stm.setString(1,name); //给将用户和密码传入stm对象中,表的起始列从1开始。
stm.setString(2,pwd);
ResultSet res= stm.executeQuery();//不需要传参数。
6. 数据库连接池
数据库连接池,和线程池类似。连接池里建立了很多connection,当用户来连接数据库时候,池中的connection会用户和数据库连接起来;当用户离开,connection在回到池中,等待下一个用户,这就好比如物品循环利用。
如果不适用连接池,那么每一个用户访问数据库是都要重新建立一个connenction对象,断开数据库又要销毁connection,这个开销是非常大的。