JDBC
JAVA的数据获取方式
①声明变量并赋值
②Scanner控制台输入
③IO流(将硬盘数据读取到java)
④socket+io流
⑤从数据库中获取
概念
Java与数据库之间的沟通不一致, 数据库厂商提供了接口以及提供了驱动包,Java实现接口就可以操作数据库。
所以JDBC就是数据厂商对外提供的能够对自己操作的驱动包也就是jar文件
使用
①加载驱动类 Class.forname
②获取数据库连接对象 Connection conn = DriverManager.getConnection();
③ 设置提交方式为手动提交 conn.setAutoCommit(false)
③获取sql命令对象 Statement sta =conn.createStatement();
④获取sql命令 Srtring str = ""
⑤执行sql 命令 int i = sta.executeUpdate() 返回值表示成功修改的数据量 不论增删改都是executeUpdate()
⑥关闭资源 sta.close() conn.close()
删除不存在的数据不报错
常见错误
class not found 驱动没找到
SQLEXCEPTION URL错误
SQLSynTaxException SQL语句错误
代码展示
Connection conn=null;
Statement stmt=null;
//声明JDBC参数
String driver="oracle.jdbc.driver.OracleDriver";
String url="jdbc:oracle:thin:@localhost:1521:orcl";
String username="scott";
String password="oracle";
//1 加载驱动类
try {
Class.forName(driver);
//2 获取数据库连接对象(连接指定的数据库)
conn=DriverManager.getConnection(url,username,password);
conn.setAutoCommit(false);
//3 获取sql命令对象(编译和发送sql命令给数据库)
stmt=conn.createStatement();
//4 创建sql命令
String sql="insert into dept values(97,'吃鸡学院','北京')";
//5 指定sql命令
int i=stmt.executeUpdate(sql);
coon.submit()
System.out.println("执行结果:"+i);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//6 关闭资源
try {
stmt.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
coon.rollback
}
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
增删查代码基本都一样 都是用 executeUpdate
查是 executeQuery 返回类型为Resultset (基于指针类似枚举) 但是查询时候i不方便,尽量转换成arraylist .并且根据数据库表创建相应的类 ,则一个对象含有一组数据保证了数据的完整性。
使用resultset时候 resultset最后要关闭 Resultset re =new Resultset() re.close()
事务管理
JDBC为自动提交 后一条语句错了前一条也会提交 比如银行转账 一个人给另一个人转1000 看为两个SQL语句,第二个错了即第二个人收不到钱,但是第一个人钱也已经转出去了 会出现问题。 手动提交则有一个错误就不提交。增删改设置手动提交,查可以不设置。
概念:一个事物完成需要多个事物协助完成
上图代码已经添加手动提价功能
开发步骤
业务需求分析
数据库设计
sql语句设计
数据库操作功能实现
业务逻辑代码实现
联合测试
上线测试
维护
PreparedStatement对象完成查询
原因:使用statement可能存在sql注入风险
①加载驱动类 Class.forname
②获取数据库连接对象 Connection conn = DriverManager.getConnection();
// ③ 设置提交方式为手动提交 conn.setAutoCommit(false)
④获取sql命令 Srtring str = "select * from where uname=? and upwd =?"
③获取sql命令对象 PrepareStatement ps =coon.prepareStament(str)
④ 给占位符赋值 ps.setString(1,“liming”) 不知道类型就setObject()
⑤执行sql 命令 int i = ps.executeUpdate() 返回值表示成功修改的数据量 不论增删改都是executeUpdate()
⑥关闭资源 sta.close() conn.close()
优点:
防止了sql注入
执行效率高因为有预编译 多次执行同一条sql语句 sql只编译一次 ,statement因为sql以字符串的形式存在所以使用一次要编译一次
区别:
先预编译模板sql语句 然后再创建sql命令对象 然后再实现占位符的赋值 最后再执行
statement 可以用于sql语句的拼接 prepareStatement不可以
JDBC的封装
原因:驱动加载 数据库连接对象的代码都是重复的
解决:
方法一:将变量设置到全局变量 比如username url password 但是修改数据源 比如class 则必须重启程序才能完成
方法二: 将四个参数 driver url username password 存储到properties属性配置文件中, 封装工具类进行获取
properties文件专门存储属性配置的文件 格式是键值对 以=号隔开,并且不能以;结尾 可以使用Properties对象进行读取该文件内容
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JdbcUtil {
private static String driver;
private static String url;
private static String username;
private static String password;
static{
//创建properties对象获取属性文件的内容
Properties p=new Properties();
//获取属性文件的读取流对象
InputStream is=JdbcUtil.class.getResourceAsStream("/db.properties");
try {
//加载属性配置文件
p.load(is);
//获取jdbc参数
driver=p.getProperty("driver");
url=p.getProperty("url");
username=p.getProperty("username");
password=p.getProperty("password");
//加载驱动
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//获取Connection对象
public static Connection getConnection(){
Connection conn=null;
try {
conn=DriverManager.getConnection(url, username, password);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
//封装获取PreparedStatement对象
public static PreparedStatement getPreparedStatement(String sql,Connection conn){
PreparedStatement ps=null;
try {
ps =conn.prepareStatement(sql);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return ps;
}
//封装获取Statement对象
public static Statement getStatement(Connection conn){
Statement stmt=null;
try {
stmt = conn.createStatement();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return stmt;
}
//关闭资源
public static void closeAll(ResultSet rs,Statement stmt,Connection conn){
try {
rs.close();
} catch (Exception e) {
}
try {
stmt.close();
} catch (SQLException e) {
}
try {
conn.close();
} catch (SQLException e) {
}
}
//封装DML
public static int executeDML(String sql,Object...objs){
//创建连接对象
Connection conn=getConnection();
//创建sql命令对象
PreparedStatement ps=JdbcUtil.getPreparedStatement(sql, conn);
//给占位符赋值
try {
conn.setAutoCommit(false);
for(int i=0;i<objs.length;i++){
ps.setObject(i+1, objs[i]);
}
int i=ps.executeUpdate();
conn.commit();
return i;
} catch (Exception e) {
try {
conn.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}finally{
//关闭资源
JdbcUtil.closeAll(null, ps, conn);
}
//返回结果
return -1;
}
}