1、jdbc简介
JDBC(Java Database Connectivity)是一个独立于特定数据库管理系统的。通用的SQL数据库存取和操作的公共接口(一组API),定义了用来采访数据库的标准java类库,使用这个类库可以以一种标准的方法,方便的访问数据库资源(java.sql包中)
JDBC为访问不同的数据库提供了一种统一的途径,JDBC对开发组屏蔽了一些细节问题。
JDBC的目标是使应用程序开发人员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,这样就使得程序员无需对特定的数据库系统的特点有过多的了解,从而大大简化和加快了开发过程。
JDBC包括两个层次
-
面向应用的API:Java API,抽象接口,供应用程序开发人员使用(连接数据库,执行SQL语句,获得结果集) -
面向数据库API:Java Driver API,供开发数开发数据库驱动程序
主要概念
DriverManager(java.sql.DriverManager)
装载驱动程序,管理应用程序与驱动程序之间的连接
Driver(由驱动程序开放式提供)
将应用程序的API请求转换为特定的数据库请求
Connection(java.sql.Connection)
将应用程序连接到特定的数据库
Statement
在一个给定的连接中,用于执行一个数据库SQL语句u
ResultSet
SQL语句完成 后,返回的数据库结果集(包括行、列)
2、jdbc操作
1>添加jar文件,测试jar文件是否添加成功
2>加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");//加载类
3>获取与数据库的链接
String url="jdbc:mysql:///oa?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true";
String username = "root";
String pwd="123456";
Connection connection = DriverManager.getConnection(url,username,pwd);
链接数据库需要提供什么? 链接的url 用户名 密码
5.x 链接数据库的url jdbc:mysql://localhost:3306/test 如果是本机,端口号没改变 jdbc:mysql:///test
8.x url
jdbc:mysql:///test?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true
4>创建通道,发送sql指令
Statement stmt = connection.createStatement();
创建Statement 通过改对象发送sql指令
1、execute 该方法可以发送select或者 insert update delete语句,如果是增删改方法 返回false,如果是select语句返回true
该方法不常用
2、executeUpdate 返回sql语句影响的行数
3、exexuteQuery 返回结果集
5>需要处理结果集
ResultSet
String sql="SELECT deptid did,deptname dname FROM dept";
rs = stmt.executeQuery(sql);
while(rs.next()){
int id = rs.getInt("did");//通过查询结果的列名获取数据
int id1 = rs.getInt(1);//通过列序号,从1开始
System.out.println(id+"---"+id1);
}
6>关闭资源
public static void main(String[] args) {
Connection connection = null;
Statement stmt = null;
try {
Class.forName(JDBCUtils.DRIVER);
connection = DriverManager.getConnection(JDBCUtils.URL,JDBCUtils.USERNAME,JDBCUtils.PASSWORD);
stmt = connection.createStatement();
String sql="delete from dept where deptid=3";
int rows = stmt.executeUpdate(sql);
System.out.println(rows);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(stmt!=null){
stmt.close();
}
if(connection!=null){
connection.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
Class.forName(JDBCUtils.DRIVER);
conn = DriverManager.getConnection(JDBCUtils.URL,JDBCUtils.USERNAME,JDBCUtils.PASSWORD);
stmt = conn.createStatement();
// String sql="select * from dept";
String sql="SELECT deptid did,deptname dname FROM dept";
rs = stmt.executeQuery(sql);
while(rs.next()){
int id = rs.getInt("did");//通过查询结果的列名获取数据
int id1 = rs.getInt(1);//通过列序号,从1开始
System.out.println(id+"---"+id1);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(rs!=null){
rs.close();
}
if(stmt!=null){
stmt.close();
}
if(conn!=null){
conn.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
3、sql注入与PreparedStatement
1、sql注入的含义
通过拼接特殊sql语句,获取到不该获取的数据
String sql="SELECT * FROM users WHERE uname='"+uname+"' AND upwd='"+upwd+"'";
//传入值的时候,密码传递的结果是 ' OR '1'='1 刚好拼接出一个 or '1'='1' 恒成立的条件 获取到了所有的数据
//SELECT * FROM users WHERE uname='aa' AND upwd='' OR '1'='1'
public static void main(String[] args) {
String inname ="aa";
String inpwd = "' OR '1'='1";
Connection connection = null;
Statement stmt = null;
ResultSet rs = null;
try {
Class.forName(JDBCUtils.DRIVER);
connection = DriverManager.getConnection(JDBCUtils.URL,JDBCUtils.USERNAME,JDBCUtils.PASSWORD);
stmt = connection.createStatement();
String sql="SELECT * FROM users WHERE uname='"+inname+"' AND upwd='"+inpwd+"'";
System.out.println(sql);
rs = stmt.executeQuery(sql);
while (rs.next()){
int id = rs.getInt("uid");
String name = rs.getString("uname");
String pwd = rs.getString("upwd");
System.out.println(id+"\t"+name+"\t"+pwd);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
....
//输入用户名和密码获取信息
}
如果避免,java提供了PreparedStatement 防止sql注入:在使用PreparedStatement的时候,sql语句中的参数,全部通过占位符的方式来使用,给占位符赋值
....
String sql="SELECT * FROM users WHERE uname=? and upwd=? ";
.....
pstmt = connection.prepareStatement(sql);
pstmt.setString(1,inname);
pstmt.setString(2,inpwd);
rs = pstmt.executeQuery();
public static void main(String[] args) {
String inname ="zs";
// String inpwd = "' OR '1'='1";
String inpwd="147258";
Connection connection = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
String sql="SELECT * FROM users WHERE uname=? and upwd=? ";
// String sql="SELECT * FROM users WHERE uname='"+inname+"' and upwd='"+inpwd+"' ";
try {
Class.forName(JDBCUtils.DRIVER);
connection = DriverManager.getConnection(JDBCUtils.URL,JDBCUtils.USERNAME,JDBCUtils.PASSWORD);
pstmt = connection.prepareStatement(sql);
pstmt.setString(1,inname);
pstmt.setString(2,inpwd);
rs = pstmt.executeQuery();
while (rs.next()){
int id = rs.getInt("uid");
String name = rs.getString("uname");
String pwd = rs.getString("upwd");
System.out.println(id+"\t"+name+"\t"+pwd);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
....
}
//输入用户名和密码获取信息
}
Connection connection = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
Class.forName(JDBCUtils.DRIVER);
connection = DriverManager.getConnection(JDBCUtils.URL,JDBCUtils.USERNAME,JDBCUtils.PASSWORD);
String sql="INSERT INTO dept VALUES(NULL,?,?,?)";
pstmt = connection.prepareStatement(sql);
pstmt.setString(1,"采购部");
pstmt.setString(2,"pstmt实现");
pstmt.setInt(3,5);
int rows = pstmt.executeUpdate();
System.out.println(rows);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.close(connection,pstmt,rs);
}
日期类型的处理
Java事务的类型有三种:JDBC事务、JTA(Java Transaction API)事务、容器事务。
事务
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
Connection conn = null;
Statement stmt = null;
System.out.println("请输入一个数");
int num = input.nextInt();//如果输入的是0 则代码执行不成功
try {
Class.forName(JDBCUtils.DRIVER);
conn = DriverManager.getConnection(JDBCUtils.URL,JDBCUtils.USERNAME,JDBCUtils.PASSWORD);
conn.setAutoCommit(false);//手动事务
stmt = conn.createStatement();
stmt.executeUpdate("INSERT INTO dept VALUES(NULL,'ceshinew2','xx',0)");
if(num==0){
throw new RuntimeException("数据添加失败");
}
stmt.executeUpdate("INSERT INTO dept VALUES(NULL,'ceshinew3','xx',0)");
conn.commit();
} catch (Exception e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
} finally {
JDBCUtils.close(conn,stmt,null);
}
}
打点事务
public static void test01(){
JDBCUtils jdbcUtils = new JDBCUtils();
Connection connection = null;
Statement stmt = null;
Savepoint sp = null;
Scanner input = new Scanner(System.in);
System.out.println("请输入一个数");
int num = input.nextInt();
try {
connection = jdbcUtils.getConnection();
connection.setAutoCommit(false);
stmt = connection.createStatement();
stmt.executeUpdate("update account set balance=balance-50 where accid=1");
sp = connection.setSavepoint();
stmt.executeUpdate("update account set balance=balance-5000 where accid=1");
if(num==2){
throw new RuntimeException("失败了");
}
stmt.executeUpdate("update account set balance=balance+5000 where accid=2");
} catch (SQLException throwables) {
System.err.println("发生了数据库异常");
try {
connection.rollback(sp);
} catch (SQLException e) {
e.printStackTrace();
}
}catch (RuntimeException e){
// e.printStackTrace();
System.err.println("发生未知的异常:"+e.getMessage());
try {
connection.rollback(sp);
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally {
try {
connection.commit();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
jdbcUtils.close(connection,stmt,null);
}
}
批处理
public static void test02(){
JDBCUtils jdbcUtils = new JDBCUtils();
//插入1000调记录
Connection connection = null;
PreparedStatement pstmt = null;
try {
connection = jdbcUtils.getConnection();
pstmt = connection.prepareStatement("INSERT INTO cities VALUES(NULL,?,NULL)");
long start = System.currentTimeMillis();
for(int i=1;i<=10000;i++){
pstmt.setString(1,"c"+i);
pstmt.addBatch();
if(i%1000==0){
pstmt.executeBatch();
pstmt.clearBatch();
}
}
long end = System.currentTimeMillis();
System.out.println("===="+(end-start));
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
jdbcUtils.close(connection,pstmt,null);
}
}
获取自增主键的值
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
JDBCUtils jdbcUtils = new JDBCUtils();
try {
conn = jdbcUtils.getConnection();
pstmt = conn.prepareStatement("INSERT INTO cities VALUES(NULL,'c',NULL),(NULL,'c2',NULL);", Statement.RETURN_GENERATED_KEYS);
pstmt.executeUpdate();
rs = pstmt.getGeneratedKeys();//为什么自增主键放到结果集中,因为一条sql语句可能插入多条记录
while (rs.next()){
Object id = rs.getObject(1);
System.out.println(id);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
jdbcUtils.close(conn,pstmt,rs);
}
}
callabledStatement的使用
public static void test01(){
Connection conn = null;
CallableStatement cstmt = null;
JDBCUtils jdbcUtils = new JDBCUtils();
try {
Class.forName("com.mysql.cj.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql:///mydb?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true","root","123456");
cstmt = conn.prepareCall("{call demo08(?,?,?,?)}");
cstmt.setInt(1,3);//输入类型的
cstmt.registerOutParameter(2, Types.VARCHAR);//输出的类型
cstmt.registerOutParameter(3,Types.VARCHAR);
cstmt.registerOutParameter(4,Types.INTEGER);
cstmt.execute();
String name = cstmt.getString(2);
String subname = cstmt.getString(3);
int score = cstmt.getInt(4);
System.out.println(name+"\t"+subname+"\t"+score);
} catch (Exception e) {
e.printStackTrace();
} finally {
jdbcUtils.close(conn,cstmt,null);
}
}
public static void test02(){
Connection conn = null;
CallableStatement cstmt = null;
JDBCUtils jdbcUtils = new JDBCUtils();
try {
Class.forName("com.mysql.cj.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql:///mydb?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true","root","123456");
cstmt = conn.prepareCall("{?=call fun_02(?)}");//函数有返回值,第一个?接收饭盒的结果
cstmt.registerOutParameter(1,Types.VARCHAR);
cstmt.setInt(2,2);
cstmt.execute();
String res = cstmt.getString(1);
System.out.println(res);
} catch (Exception e) {
e.printStackTrace();
} finally {
jdbcUtils.close(conn,cstmt,null);
}
}
4、内容回顾
1>jdbc意义 接口 具体的实现是各个数据库厂商做的实现
2>jdbc使用步骤
添加Jar
加载驱动
获取链接
创建通道 发送sql指令
处理结果集
关闭资源
3>Statement sql注入
4>RestultSet next() getXXX()
5>PrepareStatement ? 占位符的方式
6>事务与批处理 主键自增 自动事务,可以设置手动 打点事务 pstmt批处理
7>CallabledStatement 调用存储过程和存储 函数的
5、面向对象的思想操作数据库
java 数据库【crud操作】
类 表
属性类型 列类型
属性属性名 列名
对象 记录
业务中也是crud操作
分层:单人单职
bean:实体类,与数据库表对应的,属性和数据库的字段对应
dao:数据访问层,与底层数据交互
view:与使用软件的人交互
|