JDBC(Java Data Base Connectivity,Java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。
JDBC为开发人员提供了一个标准的API,据此可以构建更高级的工具和接口,使数据库开发人员能够使用java API编写数据库应用程序,并且可跨平台运行,并且不受数据库供应商的限制。
JDBC为我们提供了java连接数据库的驱动。而这个驱动也是由Java开发出来的,我们只需要将这个驱动放进项目中,通过这个驱动,我们就可以用Java连接数据库,进行数据库的管理操作。
了解:JDBC与ODBC的区别
二者皆可以实现对数据库的操作(连接、增删改查、建库建表)。
JDBC是SUN开发的java连接数据库的标准
ODBC是微软开发的,C语言的
DriverManager: 用于注册驱动
Connection: 表示与数据库创建的连接
Statement: 操作数据库sql语句的对象
ResultSet: 结果集或一张虚拟表
注册驱动(只做一次)
建立数据库连接
创建执行SQL的语句(Statement)
执行SQL语句
注:如果是查询,需要处理执行的结果(如:接收查询数据)
释放资源(千万不要漏了)
1、java.sql.DriverManager类:创建连接
a、注册驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver()); //不建议使用
原因有2个:
导致驱动被注册2次
强烈依赖数据库的驱动jar
解决办法:
Class.forName("com.mysql.jdbc.Driver");
b、与数据库建立连接
static Connection getConnection(String url, String user, String password)
//试图建立到给定数据库 URL 的连接。
getConnection("jdbc:mysql://localhost:3306/jdbc01", "root", "root");
URL:SUN公司与数据库厂商之间的一种协议。
jdbc:mysql://localhost:3306/db01
协议 子协议 IP : 端口号 数据库
mysql: jdbc:mysql://localhost:3306/db01 或者 jdbc:mysql:///db01(默认本机连接)
oracle: jdbc:oracle:thin:@localhost:1521:sid
getConnection(String url, Properties info)
getConnection(String url)
DriverManager.getConnection("jdbc:mysql://localhost:3306/db01?user=root&password=root");
2、java.sql.Connection接口:一个连接(桥)
接口的实现在数据库驱动中。所有与数据库交互都是基于连接对象的。
Statement createStatement(); //创建操作sql语句的对象
3、java.sql.Statement接口:操作sql语句,并返回相应结果的对象(小货车)
接口的实现在数据库驱动中。用于执行静态 SQL 语句并返回它所生成结果的对象。
ResultSet executeQuery(String sql) //根据查询语句返回结果集。只能执行select语句。
int executeUpdate(String sql) //根据执行的DML(insert update delete)语句,返回受影响的行数。
boolean execute(String sql) //此方法可以执行任意sql语句。返回boolean值,表示是否返回ResultSet结果集。
//仅当执行select语句,且有返回结果时返回true, 其它语句都返回false;
4、java.sql.ResultSet接口:结果集(客户端用来存表数据的对象)
a、封装结果集的。
提供一个游标,默认游标指向结果集第一行之前。
调用一次next(),游标向下移动一行。
提供一些get方法。
封装数据的方法
Object getObject(int columnIndex); 根据序号取值,索引从1开始
Object getObject(String ColomnName); 根据列名取值。
将结果集中的数据封装到JavaBean中
Java的数据类型与数据库中的类型的关系
Java数据类型 | 数据库数据类型 |
---|---|
byte | tityint |
short | smallint |
int | int |
long | bigint |
float | float |
double | double |
String | char/varchar |
Date | date |
boolean next() //将光标从当前位置向下移动一行
// 有两种方式获取字段值,1.通过下标;2.通过字段名
int getInt(int colIndex) //以 int 形式获取ResultSet结果集当前行指定列号值
int getInt(String colLabel)
float getFloat(int colIndex) //以 float 形式获取ResultSet结果集当前行指定列号值
float getFloat(String colLabel)
String getString(int colIndex) //以 String 形式获取ResultSet结果集当前行指定列号值
String getString(String colLabel)
Date getDate(int columnIndex)
Date getDate(String columnName)
void close() //关闭 ResultSet 对象
b、可移动游标的方法
boolean next() //将光标从当前位置向前移一行。
boolean previous()
//将光标移动到此 ResultSet 对象的上一行。
boolean absolute(int row) //参数是当前行的索引,从1开始
//根据行的索引定位移动的指定索引行。
void afterLast() //将光标移动到末尾,正好位于最后一行之后。
void beforeFirst()
//将光标移动到开头,正好位于第一行之前。
5、释放资源
资源有限,要正确关闭。
> JDBC规范在哪里:
JDK中:
java.sql.*;
javax.sql.*;
> 数据库厂商提供的驱动:jar文件
*.jar(例如mysql-connector-java-5.0.8.jar)
1、创建java工程
项目名的命名规范:项目名全部小写。创建一个java工程。
2、导入jar包
使用JDBC操作数据库,需要导入JDBC的驱动包:mysql-connector-java-5.0.8.jar。
在项目下面创建一个文件夹:lib,将驱动包复制到lib下面,并将jar包加载到项目中,如下图所示:
l 新建lib文件夹:
l 将jar包复制到lib文件夹下面:
l 选中jar包,单击右键,在弹出的窗口中选择“Add to Build Path” ,将jar包加载到项目中
代码:
//dbinfo.properties
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql:///db01
username=root
password=root
//User.java
public class User {
private int id;
private String name;
private String password;
private String email;
private Date birthday;
//此处省略一堆的各个属性的get方法和set方法
}
//这里自定义一个DBUtils工具类
public class DBUtils {
private static String driverClass;
private static String url;
private static String username;
private static String password;
static{
//此对象是用于加载properties文件数据的
ResourceBundle rb = ResourceBundle.getBundle("dbinfo");
driverClass = rb.getString("driverClass");
url = rb.getString("url");
username = rb.getString("username");
password = rb.getString("password");
try {
Class.forName(driverClass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//得到连接的方法
public static Connection getConnection() throws Exception{
return DriverManager.getConnection(url, username, password);
}
//关闭资源的方法
public static void closeAll(ResultSet rs,Statement stmt,Connection conn){
//关闭资源
if(rs!=null){
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
}
rs = null;
}
if(stmt!=null){
try {
stmt.close();
} catch (Exception e) {
e.printStackTrace();
}
stmt = null;
}
if(conn!=null){
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
conn = null;
}
}
}
//TestCRUD.java
public class TestCRUD {
@Test
public void testSelect(){
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = DBUtils.getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery("select * from users");
List list = new ArrayList();
while(rs.next()){
User u = new User();
u.setId(rs.getInt(1));//或 u.setId(rs.getInt("id"));
u.setName(rs.getString(2));//或 u.setName(rs.getString("name"));
u.setPassword(rs.getString(3));
u.setEmail(rs.getString(4));
u.setBirthday(rs.getDate(5));
list.add(u);
}
for (User user : list) {
System.out.println(user);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
DBUtils.closeAll(rs, stmt, conn);
}
}
@Test
public void testInsert(){
Connection conn = null;
PreparedStatement stmt = null;
try {
conn = DBUtils.getConnection();
stmt = conn.prepareStatement("INSERT INTO users VALUES(?,?,?,?,?)");
stmt.setInt(1, 5);
stmt.setString(2, "tom");
stmt.setString(3, "333");
stmt.setString(4, "[email protected]");
//stmt.setDate(5, new java.sql.Date(System.currentTimeMillis()));
stmt.setString(5, "2015-09-11");
int i = stmt.executeUpdate();
if(i>0){
System.out.println("success");
}
} catch (Exception e) {
e.printStackTrace();
}finally{
DBUtils.closeAll(null, stmt, conn);
}
}
@Test
public void testUpdate(){
Connection conn = null;
PreparedStatement stmt = null;
try {
conn = DBUtils.getConnection();
stmt = conn.prepareStatement("UPDATE users SET NAME=?,PASSWORD=?,email=? WHERE id=?");
stmt.setString(1, "jerry123");
stmt.setString(2, "123");
stmt.setString(3, "[email protected]");
stmt.setInt(4, 5);
int i = stmt.executeUpdate();
if(i>0){
System.out.println("success");
}
} catch (Exception e) {
e.printStackTrace();
}finally{
DBUtils.closeAll(null, stmt, conn);
}
}
@Test
public void testDelete(){
Connection conn = null;
Statement stmt = null;
try {
conn = DBUtils.getConnection();
stmt = conn.createStatement();
int i = stmt.executeUpdate("DELETE FROM users WHERE id=4");
if(i>0){
System.out.println("success");
}
} catch (Exception e) {
e.printStackTrace();
}finally{
DBUtils.closeAll(null, stmt, conn);
}
}
}
Statement
与PreparedStatement
两者都可以把SQL语句从Java程序发送到指定数据库,并执行SQL语句,但是他们也具有如下区别:
Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出;
PreparedStatement会形成预编译的过程,对于多次重复执行的语句,PreparedStatement的效率要高一些,而且适合批处理数据(批量添加);
最重要的是,PreparedStatement能有效防止危险自负的注入,即SQL注入问题。
根据比较结果可知,我们需要选用PreparedStatement更好、更快速、更安全。因此,在以后的JDBC操作中,建议使用PreparedStatement。
Statement接口提供了两种常用的执行SQL语句的方法:executeQuery、executeUpdate。
PreparedStatement接口继承自Statement。PreparedStatement在sql语句中通过使用占位符?
来代替常量字段值,setXXX方法来填充字段值,取代掉占位符,形成完整的可执行的sql语句。
conn = DBUtils.getConnection();
stmt = conn.prepareStatement("INSERT INTO users VALUES(?,?)");
stmt.setInt(1, 5);
stmt.setString(2, "tom");
stmt.executeUpdate();
一次性执行多条SQL语句(比如:一次下单购买多个商品)。
执行批量添加数据时,务必要将提交方式设置为手动提交。
con.setAutoCommit(false);//将提交方式设置为手动提交
在获取到连接后,获取PreparedStatement对象之前,需要将提交方式设置为手动提交。
在循环中,可以使用ps.addBatch()
将给定的 SQL命令添加到此Statement对象的当前命令列表中。
循环结束后,使用ps.executeBatch()
,可以将一批SQL命令提交给数据库,但是该方法之后必须要使用con.commit()
,该命令是命令数据库新更改的数据成为持久化的数据。
@Test
public void testAddBatch(){
Connection con = BaseDao.getConn();
//批量添加数据
PreparedStatement ps = null;
try {
con.setAutoCommit(false);//将提交方式设置为手动提交
String sql = "insert into test(id,name,password) values(?,?,?)";
ps = con.prepareStatement(sql);
long start = System.currentTimeMillis();//获取当前系统时间的毫秒数
for (inti = 0; i < 3000;i++) {
ps.setInt(1, (i+1));
ps.setString(2, "用户"+i);
ps.setString(3, MD5Util.GetMD5Code("密码"+i));
ps.addBatch();//将给定的SQL命令添加到此Statement对象的当前命令列表中。
}
System.out.println("数据循环耗时:"+(System.currentTimeMillis()-start)+"ms");
start = System.currentTimeMillis();//获取当前系统时间的毫秒数
//将一批命令提交给数据库来执行,如果全部命令执行成功,则返回更新计数组成的数组
ps.executeBatch();
con.commit();//提交
System.out.println("数据执行SQL耗时:"+(System.currentTimeMillis()-start)+"ms");
} catch (Exceptione) {
e.printStackTrace();
}finally {
BaseDao.close(con, ps, null);
}
}
采用批量处理数据的优点:
减少访问数据库的次数,大大提高了批量SQL执行的效率。
在使用动态SQL为like赋值的时候,like直接使用?
即可。PreparedStatement对象为占位符赋值的时候,我们需要把百分号%
拼接进去即可。
案例:
String sql = "select * from user where username like ?";
ps.setString(1,"%"+参数值+"%");
参考自《JDBC》