数据库驱动:数据库厂商提供的用来操作数据库的jar包
JDBC:
由于各大数据库厂商提供的驱动各不相同,导致学习成本很高,sun公司为了简化数据库操作,提供了一套规范,本质上就是一大堆接口,要求各大数据库厂商实现jdbc这套接口,此后只需学会jdbc这套接口,就可以操作所有数据库了。
JDBC已经被集成到jdk中,可以直接使用,所在的包为:java.sql、javax.sql
但是在操作数据库时,还需要导入具体的数据库驱动jar包
首先,导入MySQL的驱动jar包
创建一个目录,名称为lib
将MySQL驱动jar包(mysql-connector-java-5.0.8-bin.jar)拷贝到lib目录下
将jar包加入当前工程
Connection:
代表数据库连接的对象,客户端和数据库的所有交互都是通过此对象完成
获取Connection:
Connection conn = DriverManager.getConnection( "jdbc:mysql:///mydb1", "root", "root");
其中url完整写法为:“jdbc:mysql://ip:端口/库名”
如果ip为本机,端口号为3306,可以省略
方法:
createStatement() :获取传输器
prepareStatement(sql) :获取预编译的传输器
注意:
使用完Connection对象后,需要释放资源,因为Connction是非常宝贵的资源,使用完成后要及时释放,所有释放资源的方法都要写到finally中,确保资源一定可以被释放…
Statement:此对象用于向数据库发送sql,返回执行结果
常用的方法:
executeQuery(sql): 执行查询语句,返回ResultSet
** executeUpdate(sql)**:执行增删改的语句,返回int表示被影响的行数
注意:
此对象使用完也要释放,在释放Connection之前释放
ResultSet
此对象表示查询语句执行的结果,在ResultSet中,维护了一个指向表格行的游标,初始时,游标在第一行的前面,每次调用next()方法,游标向下移动一行
常用的方法:
操作游标
next():游标向下移动一行,如果有数据返回true,否则返回false
previous():向上移动一行,如果有数据返回true,否则返回false
absolute(int row):移动到指定行
beforeFirst():移动到第一行的前面
afterLast():移动到最后一行的后面
获取数据
getString("field_name"):返回String类型的数据
getInt("field_name"):返回int类型的数据
getDouble("field_name"):返回double类型的数据
getObject("field_name"):返回Object类型的数据
注意:
此对象使用完也要释放,在释放Statement之前释放
实现代码:
package cn.tedu.jdbc;
import java.sql.*;
public class JDBCSelect {
public static void main(String[] args) {
Connection conn = null;
Statement stat = null;
ResultSet rs = null;
try {
//1.注册数据库驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接
conn = DriverManager.getConnection(
"jdbc:mysql:///mydb1", "root", "root");
//3.获取传输器
stat = conn.createStatement();
//4.利用传输器发送sql,返回结果
rs = stat.executeQuery("select * from exam");
//5.处理结果
while (rs.next()){
String name = rs.getString("name");
double math = rs.getDouble("math");
System.out.println(name+" : "+math);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//6.释放资源
if(rs != null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
rs = null;
}
}
if(stat != null){
try {
stat.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
stat = null;
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
conn = null;
}
}
}
}
}
由于后台的SQL是拼接而来,其中的参数是用户提交的,如果用户在提交参数时,提交了一些SQL关键字或者特殊符号,有可能导致SQL语意发生改变,从而造成一些意外操作。
PreparedStatement是statement的子类
优点:
(1)可以防止注入攻击
在创建PreparedStatement对象时,已经确定并预编译了SQL的骨架,后面发送的只能是参数的值,不影响SQL的骨架,即使参数中有特殊符号,也只是当成普通字符串处理
(2)省去了拼接参数的麻烦
(3)提高了程序的效率
骨架预编译后,会缓存下来,如果下次执行的SQL和这个骨架匹配,则直接使用缓存的骨架,不会重新编译
假设有一大堆sql要执行,如果一条一条发送,效率低下
可以通过批处理,将一大堆sql放到一个批中,一起发送给数据库
package cn.tedu.batch;
import cn.tedu.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
//Statement实现批处理
public class StateBatch {
public static void main(String[] args) {
Connection conn = null;
Statement stat = null;
ResultSet rs = null;
try{
conn = JDBCUtils.getConnection();
stat = conn.createStatement();
//将sql添加到批中
stat.addBatch("use mydb1");
stat.addBatch("create table stu(id int,name varchar(20))");
stat.addBatch("insert into stu values(1,'aaa')");
stat.addBatch("insert into stu values(2,'bbb')");
stat.addBatch("insert into stu values(3,'ccc')");
stat.addBatch("insert into stu values(4,'ddd')");
//执行批
stat.executeBatch();
}catch (Exception e){
e.printStackTrace();
}finally {
JDBCUtils.close(conn,stat,rs);
}
}
}
package cn.tedu.batch;
import cn.tedu.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
//PreparedStatement实现批处理
public class PsBatch {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try{
conn = JDBCUtils.getConnection();
ps = conn.prepareStatement("insert into stu values(?,?)");
for (int i=0;i<100;i++){
ps.setInt(1,i);
ps.setString(2,"xxx"+i);
ps.addBatch();
}
ps.executeBatch();
}catch (Exception e){
e.printStackTrace();
}finally {
JDBCUtils.close(conn,ps,rs);
}
}
}
总结:
Statement实现批处理
优点:可以添加不同结构的sql语句
缺点:不能防止注入攻击
PreparedStatement实现批处理
优点:可以防止注入攻击
缺点:只能添加相同或者相似结构的sql语句
用户每次请求都要向数据库获取连接,而数据库创建连接需要耗费较大的资源,例如一个网站一天有100万个访问,就需要创建和销毁100万次,极大的浪费了服务器的性能
所以我们可以设置一个连接池,在程序启动时就初始化一批连接,在程序中共享,需要连接时从连接池获取,用完之后再还会连接池,这样大大减少了连接的创建和销毁次数,提高了程序的效率
C3p0是开源的,常用的连接池
导包:将c3p0的jar包:c3p0-0.9.1.2.jar 拷贝到lib目录下
在src下创建一个C3p0的配置文件(C3p0提供了默认的配置文件:c3p0.properties 或者 c3p0-config.xml)
创建连接池:ComboPooledDataSourcepool=newComboPooledDataSource();
c3p0.properties 的配置内容:
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql:///mydb1
c3p0.user=root
c3p0.password=root
===============================
c3p0-config.xml的配置内容:
com.mysql.jdbc.Driver
jdbc:mysql:///mydb1
root
root
package cn.tedu.utils;
import java.sql.*;
public class JDBCUtils {
//获取连接
public static Connection getConnection(){
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection(
"jdbc:mysql:///mydb1","root","root");
return conn;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
//释放资源
public static void close(Connection conn,Statement stat,ResultSet rs){
if(rs != null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
rs = null;
}
}
if(stat != null){
try {
stat.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
stat = null;
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
conn = null;
}
}
}
}
package cn.tedu.c3p0;
import cn.tedu.utils.JDBCUtils;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
public class C3p0Demo1 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try{
//创建连接池
ComboPooledDataSource pool = new ComboPooledDataSource();
//从连接池获取连接
conn = pool.getConnection();
ps = conn.prepareStatement("delete from exam where id=?");
ps.setInt(1,2);
ps.executeUpdate();
}catch (Exception e){
e.printStackTrace();
}finally {
JDBCUtils.close(conn,ps,rs);
}
}
}