Jdbc高级编程
1.JDBC就是Java链接数据库进行增删改查(curd)
Jdbc是一种用于执行sql语句的java api,可以为多个数据库提供统一的访问方式,它是由java语言编写的类和接口组成;
在没有jdbc之前程序员是怎么做的
没有jdbc的时候,java程序员编写了一套程序连接mysq 数据库,那么我就要连接mysql的驱动api,再连接。想要换到连接oracle数据库,这个时候又需要连接oracle驱动api。
这个时候sun公司提供了一套统一的规范(接口),然后所有的数据库厂商提供了这些接口的实现类,这套规范其实就jdbc
2.Jdbc 入门
只有以下四步骤:
2.1 导入jar包,加载驱动
Class.forname(‘驱动路径‘);
Class.forname(“com.mysql.jdbc.Driver”);
2.2 获取链接(java代码和数据库链接 url username password)
Connection 定义一个对象名= Drivermanager.getConnection(url,user,passwor);
端口号是应用程序的唯一标识
Jdbc 协议:数据库类型://地址:端口号:/具体数据库
2.3 基本操作
编写sql语句;
Update 表名 set 字段名 = 目标值 where 字段名 = 目标值;//将具体一条记录改变
Delete from 表名 where 字段名 = 目标值;//删除一条记录
Insert into 表名 values (内容……);添加所有内容;
Insert into 表名(字段名字1,字段名字2…) values (值1,值2….).//具体字段添加内容
Select :查询:
2.4 释放资源
与上面的2.1—2.4一一对应
第一步:驱动的导入和加载:(一般来说驱动都导入了的,只需要导包即可)
驱动的导入
1从项目文件夹名字下 (new一个)新建floder文件夹命名位lib(library的意思)
2将文件拷贝到lib文件下;
3找到拷贝好的文件,然后选中此文件,再右键,选择Build Path 就行了
驱动的位置:
要么记住位置
要么在导入的jar包内部找到Driver文件 此文件是不带后缀名的
然后选中,右键 选择Copy Qualified Name 这样驱动的路径就复制到鼠标上了,只需要praste
驱动的加载
Class.forName(驱动路径);
第二步:获取链接 Connection
格式:
Connection 链接名字 = DriverManager.getConnection();
第三步:基本操作
第四步:connection 、Statement 、PreparedStatement、ResultSet的释放
例子:
写一个使用jdbc操作数据库db1中的user表 以下的都是user的操作,
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//第一步加载驱动
Class.forName("com.mysql.jdbc.Driver");
//第二步获取链接
Connection cnct = DriverManager.getConnection//要释放
("jdbc:mysql://localhost:3306/db1","root","123");
解释:
jdbc:mysql://localhost:3306/db2
jdbc 协议
mysql 连接mysql
localhost :连接数据库的ip地址 192.168.3.111 ,
localhost 本地
3306 端口号
db2 库名
System.out.println(cnct);//这一步可以看connection是否链接正确
//第三步
//写sql语句
String s1 = "select *from exam";
//获取执行sql语句的对象
Statement st1 = cnct.createStatement();//要释放
//执行sql语句
ResultSet result = st1.executeQuery(s1);//要释放
while(result.next()) {
System.out.print(result.getInt("id")+" ");
System.out.print(result.getString("name")+" ");
System.out.print(result.getInt("english")+" ");
System.out.print(result.getInt("chinese")+" ");
System.out.print(result.getInt("math")+" ");
System.out.println();
}
//第四步:释放资源
result.close();
st1.close();
cnct.close();
}
}
最基本的insert delete update select 语句的书写
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 使用方法来完成CURD 原始代码
* @author zj
*/
public class JdbcDemo2 {
public static void main(String[] args) {//这里是主函数调用下面的方法
try { //捕获异常
//有可能出现异常的代码
demo2();
} catch (ClassNotFoundException | SQLException e) {
//如果出现异常了 就执行这里的代码
e.printStackTrace();
}
}
//插入方法 insert 添加内容的语句
public static void demo1() throws ClassNotFoundException, SQLException {
//1加载驱动com.mysql.jdbc.Driver.class
Class.forName("com.mysql.jdbc.Driver");
// 2:获取连接
Connection conn = DriverManager.getConnection
("jdbc:mysql://localhost:3306/day05", "root", "123");
// 3:基本操作
//3.1 获取执行sql语句的对象 使用connecttion对象来创建
Statement stmt = conn.createStatement();
//3.2 编写sql语句
String sql = "insert into user values(null,'ccc','111','喜羊羊',6)";
//3.3 执行sql语句 num 是执行了几条语句 使用connection创建的对象来调用executeUpdate
int num = stmt.executeUpdate(sql);//返回值是一个int 并且调用成功就返回值1,失败返回0
if(num>0) {
System.out.println("用户保存成功");
}
// 4:释放资源
stmt.close();
conn.close();
}
//删除的方法 delete 某条记录
public static void demo2() throws ClassNotFoundException, SQLException {
//1加载驱动com.mysql.jdbc.Driver.class
Class.forName("com.mysql.jdbc.Driver");
// 2:获取连接
Connection conn = DriverManager.getConnection
("jdbc:mysql://localhost:3306/day05", "root", "123");
// 3:基本操作
//3.1 获取执行sql语句的对象
Statement stmt = conn.createStatement();
//3.2 编写sql语句
String sql = "delete from user where id =3";
//3.3 执行sql语句 num 是执行了几条语句
int num = stmt.executeUpdate(sql);
if(num>0) {
System.out.println("用户删除成功");
}
// 4:释放资源
stmt.close();
conn.close();
}
//更改的方法 update
public static void demo3() throws ClassNotFoundException, SQLException {
//1加载驱动com.mysql.jdbc.Driver.class
Class.forName("com.mysql.jdbc.Driver");
// 2:获取连接
Connection conn = DriverManager.getConnection
("jdbc:mysql://localhost:3306/day05", "root", "123");
// 3:基本操作
//3.1 获取执行sql语句的对象
Statement stmt = conn.createStatement();
//3.2 编写sql语句
String sql = "update user set username ='懒洋洋' where id = 4";
//3.3 执行sql语句 num 是执行了几条语句
int num = stmt.executeUpdate(sql);
if(num>0) {
System.out.println("用户更改成功");
}
// 4:释放资源
stmt.close();
conn.close();
}
}
创建一个工具类
从以上的insert delete update方法可以看出;有四部分重复
1 驱动加载
2 获取链接 (当数据库改变的时候链接也要改变但这里一般使用一个数据库,所有就封装起来)
3 insert delete update 内部的基本操作 它们都调用同一个方法executeUpdate(写一个封装的方法:传递一个sql语句字符串)
Select使用的executequery方法
4 释放
由于加载驱动和获取连接以及释放资源的代码都一样,创建一个工具类,以后这个代码就直接使用工具类里的,不需要自己重复写。
工具类代码如下:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
//定义的工具类的名字
public class JDBCUtils {
private static final String s = "com.mysql.jdbc.Driver";
private static final String url = "jdbc:mysql://localhost:3306/db1";
private static final String user = "root";
private static final String password = "123";
// private static final String test = "select *from student";
//加载驱动的方法 lodeDriver 无参数
public static void lodeDriver() throws ClassNotFoundException {
Class.forName("com.mysql.jdbc.Driver");
}
//创建链接的方法getConnection 返回值是个Connection 无参数
public static Connection getConnection() throws ClassNotFoundException, SQLException {
lodeDriver();
//可以直接创建链接跳过,驱动加载的步骤,因为有前面的lodeDriver()
return DriverManager.getConnection(url, user, password);
}
//以下释放语句1 close 有参数一个为Connection 另一个为Statement
//注意 preparedStatement 是 Statement的子类所以也可以调用此方法
public static void close(Connection cnt,Statement st ){
try {
cnt.close();
st.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//以下释放语句2 三个参数 因为select语句中有着 ResultSet这个对象
public static void close(Connection cnt,Statement st,ResultSet rs){
try {
cnt.close();
st.close();
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//添加内容的语句;参数为sql语句,并且返回String作为标记添加成功或者失败
//此方法 @author ygj
public static String add(String str) throws SQLException, ClassNotFoundException {
Connection cnt = getConnection();
Statement st = cnt.createStatement();
int num = st.executeUpdate(str);
// st.executeQuery(str);
if(num>0) {
return "success";
}else{
return "failed";
}
}
Sql注入问题(重要)例子:登陆
先使用statement对象来做 会出现注入
最后改进使用preparedStatement对象来做 就可以了
下面代码是使用statement对象来做的登录
使用的是user代码
Use db1;
Create table user(
id int primary key auto_increment ,
name varchar(20),
password int);
insert into user values(null,’张三’,123);
insert into user values (null,’李四’,125);
以下是使用statement对象执行sql语句
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.util.JDBCUtils;//导入自己创建的工具类包
//创建使用Statement执行sql语句的类 类名叫做UserDao_Statement
public class UserDao_Statement {
//定义名叫login的非静态方法,返回值是一个boolean类型
//要做登陆,自然要比较登陆名以及密码,所以两个参数 都是String类型;
//注意在表中password是int类型(无论是int 类型和字符串相加 结果也是一个字符串)
public boolean login(String name,String pwd) {//两个参数 返回boolean
Connection cnt = null;
Statement st=null;
ResultSet rs=null ;
try {
//加载驱动和创建链接
cnt = JDBCUtils.getConnection();//调用jdbcutils里面的创建链接的方法
//编写sql语句
String str = "select *from user where name ='"+name+"'and password ='"+pwd+"'";
//要特别注意这几个单引号
//注意这里的password int 类型,当它加上了单引号会不会报错;答案是不会报错
pwd有引号:Where name = ‘张三’ and password = ‘123’;
pwd无引号:Where name = ‘张三’ and password = 123;
以上的查询结果相同
//使用connection获取对象
st = cnt.createStatement();//上面提到 st是个Statement类型
//使用上面的对象执行select语句
rs = st.executeQuery(str);//返回只有一条语句 rs是个ResultSet类型
//JDBCUtils.getConnection().createStatement().executeQuery(str);
//这句话将加载驱动、创建链接、获取对象、执行select语句合为一句了
if(rs.next()) {//用的if语句 做登陆不会有两个相同的名字
//rs.next() 如果有下一个则返回true
//get后面的和表的字段类型一致
//括号内的和字段名字一致 加上双引号
System.out.println(rs.getInt("id"));
System.out.println(rs.getString("name"));
System.out.println(rs.getInt("password"));
return true;
}
} catch (ClassNotFoundException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//finally语句始终要执行:用来做释放语句最好了
JDBCUtils.close(cnt, st, rs);
}
return false;
/*注意这两个return try和catch里面的return 语句会在把try、catch和finally一起*执行完之后(没有异常自然只执行完try和finally语句)才会return,这个return是try *catch里面的return。在finally后面的return,自然没有用了。当if语句条件不满足,*则不执行if语句内部,不会有try里的return。所以最终返回最后的return
*/
//如果是finally里面有return语句,则无论如何都返回finally里面的语句
}
}
PreparedStatement对象执行sql语句(非常重要)
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.util.JDBCUtils;//导包 工具包
public class UserDao02_preparedStatement {
public boolean login(String name,String pwd) {
Connection cnt=null;
PreparedStatement pst=null ;
ResultSet rs=null;
try {
//创建连接 和加载驱动
cnt = JDBCUtils.getConnection();
//sql语句
//用问号占位
String str = "Select *from user where name =? and password = ?";
//用Connection获取prepareStatement对象,并且添加sql语句到()内 差别
pst = cnt.prepareStatement(str);
//set后面的可以是int double date String 要和括号内部的类型对应
pst.setString(1, name);
//数字1代表第一个问号,后面的是传进来的字符串
pst.setString(2, pwd);
//执行sql语句 对象.executeQuery()
rs = pst.executeQuery();
if(rs.next()) {
System.out.println(rs.getInt("id"));
System.out.println(rs.getString("name"));
System.out.println(rs.getInt("password"));
return true;
}
} catch (ClassNotFoundException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
JDBCUtils.close(cnt, pst, rs);
}
return false;
}
}
以下是调用这两个类中方法的main
/**
* 登录案例
*对数据库比较了解
*我只要知道用户名就可以登录成功 其实是因为sql注入
*解决方案 使用
*preparedStatement 接口
*preparedStatement 接口 可以预编译 使得我书写的sql语句格式提前被规定好,以后传递过来的变量
*即使 有mysql 中的注释或关键字,都只当作字符串处理,不当作mysql中的关键字
* *
*/
public class LoginDemo {
public static void main(String[] args) {
UserDao_Statement us = new UserDao_Statement();
boolean bool = us.login("赵四' -- ", "123");
//这样也是正确结果后面的’-- 将后续语句注释掉了
//将放进去的字符串当成了sql语句
if(bool) {
System.out.println("success");
}else {
System.out.println("failed");
}
System.out.println("----------------");
UserDao02_preparedStatement us02 = new UserDao02_preparedStatement();
boolean bool02 = us02.login("赵四' -- ", "123");
//使用preparedStatement 就不存在这个问题;
//有setString(int,double,date)将其设置为了固定的格式;
//就是一个类型参数而不是sql里面的语句
if(bool02) {
System.out.println("success");
}else {
System.out.println("failed");
}
}
}
使用PreparedStatement 实现增删改查
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.util.JDBCUtils;
public class Test_preparedStatement_CURD {
public static void main(String[] args) {
insert();
update();
delete();
select();
}
//更改
public static void update() {
Connection cnt=null;
PreparedStatement pst=null;
try {
cnt = JDBCUtils.getConnection();
String str = "update user set name =? where id = ?";
pst = cnt.prepareStatement(str);
pst.setString(1, "张三");
pst.setInt(2, 3);
int num = pst.executeUpdate();
if(num>0) {
System.out.println("更改成功");
}
} catch (ClassNotFoundException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
JDBCUtils.close(cnt, pst);
}
}
//添加记录
public static void insert() {
Connection cnt=null;
PreparedStatement pst =null;
try {
cnt = JDBCUtils.getConnection();
String str = "insert into user values(null,?,?)";
pst = cnt.prepareStatement(str);
pst.setString(1, "赵本山");
pst.setInt(2, 112);
int num = pst.executeUpdate();
if(num>0) {
System.out.println("添加记录成功");
}
} catch (ClassNotFoundException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
JDBCUtils.close(cnt, pst);
}
}
//删除
public static void delete() {
Connection cnt = null;
PreparedStatement pst = null;
try {
cnt = JDBCUtils.getConnection();
String str = "delete from user where id = ?";
pst = cnt.prepareStatement(str);
pst.setInt(1, 14);
int num = pst.executeUpdate();
if(num>0) {
System.out.println("删除成功了");
}
} catch (ClassNotFoundException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
JDBCUtils.close(cnt, pst);
}
}
//查询
public static void select () {
Connection cnt = null;
PreparedStatement pst = null;
ResultSet rs = null;
try {
cnt = JDBCUtils.getConnection();
String str= "select *from user";
pst = cnt.prepareStatement(str);
rs = pst.executeQuery();
while(rs.next()) {
System.out.print(rs.getInt("id")+" ");
System.out.print(rs.getString("name")+" ");
System.out.print(rs.getInt("password")+" ");
System.out.println();
}
} catch (ClassNotFoundException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
JDBCUtils.close(cnt, pst,rs);
}
}
}
Java语言中的事务手动开启事务
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.util.JDBCUtils;
public class Test_shiwu {
//事务jdbc
//事务是默认开启的
public static void main(String[] args) {
// TODO Auto-generated method stub
// update();
update2();
}
public static void update () {
Connection cnt = null;
try {
cnt.setAutoCommit(false);
String str = "update account set money = money+? where name = ?";
PreparedStatement pst = cnt.prepareStatement(str);
//小黑给钱给小白
pst.setDouble(1, -1000);
pst.setString(2, "小黑");
//执行减钱操作
pst.executeUpdate();
//执行小白加钱
pst.setDouble(1, 1000);
pst.setString(2, "小白");
pst.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//手动开启事务
public static void update2 () {
Connection cnt = null;
try {
cnt = JDBCUtils.getConnection();
//要使用链接的对象来调用事务,调用setAutoCommit();括号内部写false;
//关闭自动事务
cnt.setAutoCommit(false);
String str = "update account set money = money+? where name = ?";
PreparedStatement pst = cnt.prepareStatement(str);
//小黑给钱给小白
pst.setDouble(1, -1000);
pst.setString(2, "小黑");
//执行减钱操作
pst.executeUpdate();
int i = 10/0;
//这里演示的是算术异常,是需要程序员自己解决的(而不是try catch)为了演示才找的除零异常
//内部异常的出现直接跳转到catch里面下面的语句不会执行
//执行小白加钱
pst.setDouble(1, 1000);
pst.setString(2, "小白");
pst.executeUpdate();
//提交事务
cnt.commit();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
//如果内部出现异常则直接跳到这里来。上面的commit()是最后一句,前面都没有异常才执行
try {
//回滚,取消所有从事务开始的操作
cnt.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}