JDBC基本操作

JDBC

1、JDBC的简介

JDBC的全称是Java数据库连接(Java Database Connectivity),它是一套用于执行SQL语句的Java API。应用程序可通过这套API连接到关系型数据库,并使用SQL语句来完成对数据库中数据的查询、新增、更新和删除等操作。

应用程序访问JDBC的图示:

image-20210510130437035

--测试所需的数据库:
CREATE DATABASE jdbcStudy CHARACTER SET utf8 COLLATE utf8_general_ci;

USE jdbcStudy;

CREATE TABLE `users`(
	id INT PRIMARY KEY,
	NAME VARCHAR(40),
	PASSWORD VARCHAR(40),
	email VARCHAR(60),
	birthday DATE
);

INSERT INTO `users`(id,NAME,PASSWORD,email,birthday)
VALUES(1,"zhansan","123456","zs@sina.com","1980-12-04"),
(2,"lisi","123456","lisi@sina.com","1981-12-04"),
(3,"wangwu","123456","wangwu@sina.com","1979-12-04");

此测试所需要用到的所有JAR包:链接:https://pan.baidu.com/s/11XKXch0JFtwPTlakQ0sVcw 提取码:0201

2、第一个JDBC程序

简记口诀:贾琏欲执事(加连预执释) 引入依赖,加载驱动 连接数据库 创建预编译语句 设置参数,执行sql 关闭连接,释放资源

具体步骤如下:

(1)加载并注册数据库驱动。

(2)通过DriverManager获取数据库连接。

(3)通过Connection对象获取Statement对象。

(4)使用Statement执行SQL语句。

(5)操作ResultSet结果集。

(6)关闭连接,释放资源。

  • 加载驱动
Class.forname("com.mysql.jdbc.Driver");		//固定格式

//设置链接和用户名/密码:
String url = "jdbc:使用的数据库类型://主机地址:端口号/数据库名称?											useUnicode=true&characterEncoding=utf8&useSSL=false";
String username = "数据库用户名";
String passwd = "数据库密码";
  • 连接数据库
Connection con = DriverManager.getConnection(url, uername, passwd);
  • 创建预编译语句
Statement statement = con.createStatement();
  • 执行sql语句
String sql = "select * from jdbcstudy";
ResultSet resultset = statement.executeQuery(sql);

//输出结果:
while(resultset.next()){
    System.out.println("数据库的数据1:" + resultset.getObject("id"));
}
  • 释放资源
//开启多少个资源就要关闭多少个,先开后关:
resultset.close();
statement.close();
con.close();

2.1 JDBC中对象的解释

DriverManagerConnection

DriverManager类用于加载JDBC驱动并且创建与数据库的连接。

Connection接口代表Java程序和数据库的连接,只有获得该连接对象后,才能访问数据库,并操作数据表。

//DriverManager.registerDriver(new com.mysql.jdbc.Driver());	//不建议使用
//1、加载驱动:(固定格式)
Class.forName("com.mysql.jdbc.Driver");

Connection connection = DriverManager.getConnection(url, username, passwd);
//Connection 代表数据库:
        connection.setAutoCommit();       
		connection.commit();
        connection.rollback();

URL

//设置数据的链接:
String url = "jdbc:使用的数据库类型://主机地址:端口号/数据库名称?参数1&参数2&参数3";

Satement 执行sql对S象

Statement接口用于执行静态的SQL语句,并返回一个结果对象。Statement接口对象可以通过Connection实例的createStatement()方法获得,该对象会把静态的SQL语句发送到数据库中编译执行,然后返回数据库的处理结果。

        statement.executeQuery(String sql);		//用于查找操作,返回ResultSet
        statement.executeUpdate(String sql);	//用于增删改操作,返回一个受影响的行数
        statement.execute(String sql);			//用于增删改查操作

ResultSet 查询结果集:封装了所有查询的结果

ResultSet接口用于保存JDBC执行查询时返回的结果集,该结果集封装在一个逻辑表格中。在ResultSet接口内部有一个指向表格数据行的游标(或指针),ResultSet对象初始化时,游标在表格的第一行之前,调用next()方法可将游标移动到下一行。如果下一行没有数据,则返回false。在应用程序中经常使用next()方法作为while循环的条件来迭代ResultSet结果集。

获得指定的数据类型:

//不知道数据库列类型的时候使用:
resultSet.getObject();

//知道数据库列类型的时候使用:
resultSet.getString();
resultSet.getInt();
resultSet.getFloat();
resultSet.getDate();

遍历输出查询结果:

resultSet.next();			//移动到下一个数据
resultSet.previous();		//移动到上一个数据
resultSet.beforeFirst();	//移动到最前面
resultSet.afterLast();		//移动到最后面
resultSet.absolute(row);	//移动到指定行

2.2 代码实现

提取工具类

//定义一个db.properties文件:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql//localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false
username=root
passwd=123456
public Jdbc{
    //提取到全局作用域:
    private static String driver = null;
	private static String url = null;
	private static String username = null;
	private static String passwd = null;
    
    static {
        try{
            InputStream in = Jdbc.class.getClassLoader().getResourceAsStream("db.properties");
            Properties properties = new Properties();
            properties.load(in);
            
            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            uername = properties.getProperty("username");
            passwd = properties.getProperty("passwd");
            
            //加载驱动:
            Class.forname(driver);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    //定义一个连接数据库的方法:
    public static Connection getConnection(){
        Connection con = DriverManager.getConnection(url,username,passwd);
        return con;
    }
    
    //定义一个释放资源的方法:
    public static void release(Connection con,Statement sta,ResultSet res){
        try{
            if(con != null){
                con.close();
            }
            
        }catch(Exception e){
            e.printStackTrace();
        }
         try{
            if(sta != null){
                sta.close();
            }
            
        }catch(Exception e){
            e.printStackTrace();
        }
         try{
            if(res != null){
                res.close();
            }
            
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

编写增删改方法

//添加数据:
	Connection con = null;
	Statement sta = null;
    try{
       	con =  jdbc.getConnection();
        sta = con.createStatement();
        
        String = sql="insert into users values(4,'xxx','123456','12312312@qq.cm','2021-1-1')";
        int i  = sta.executeUpdate(sql);
        if(i > 0){
            System.out.println("添加成功");
        }
    }catch(SQLException e){
          e.printStackTrace();
      }finally{
        jdbc.release(con,sta,null);
    }
//修改数据:
	Connection con = null;
	Statement sta = null;
	try{
        con = jdbc.getConnection();
        sta = con.createStatement();
        
        String sql ="update users set name='lll' where id=4";
        int i = sta.executeUpdate(sql);
        if(i > 0){
            System.out.println("修改成功");
        }
    }catch (SQLException e) {
            e.printStackTrace();
    }finally{
        jdbc.release(con,sta,null);
    }
//删除数据:
	Connection con = null;
	Statement sta = null;
	try{
        con = jdbc.getConnection();
        sta = con.createStatement();
        
        String sql = "delete from users where id=4";
        int i = sta.executeUpdate(sql);
        if(i > 0){
            System.out.println("删除成功");
        }
    }catch (SQLException e) {
            e.printStackTrace();
    }finally{
        jdbc.release(con,sta,null);
    }

编写查方法

//查询数据:
	Connection con = null;
	Statement sta = null;
	ResultSet res = null;
	try{
        con = jdbc.getConnection();
        sta = con.createStatement();
        
        String sql = "select * from users where id=1";
        res = sta.executeQuery(sql);
        while(res.next()){
            System.out.println("输出name:" + res.getString("name"));
        }
    }catch (SQLException e) {
            e.printStackTrace();
    }finally{
        jdbc.release(con,sta,res);
    }

2.3 SQL注入问题

sql存在漏洞,会被攻击导致数据泄露。‘or’1=1

public class TestSqlinto {
    public static void main(String[] args) {
//        login("zhansan","123456");
//        login("'or'1=1","123456");      //SQL注入,不安全
        login("","'or'1=1");
    }

    //登陆业务:
    public static void login(String username,String passwd){
        Connection con = null;
        Statement sta = null;
        ResultSet res = null;

        try {
            con = Test02.getCon();
            sta = con.createStatement();

            //select * from users where   name='zhansan' and password='123456';
            String sql = "select * from users where NAME='"+username+"' and 											PASSWORD='"+passwd+"'";
            res = sta.executeQuery(sql);

            while (res.next()){
                System.out.println("输出ID:" + res.getInt("id"));
                System.out.println("输出name:" + res.getString("NAME"));
                System.out.println("输出password:" + res.getString("PASSWORD"));
                System.out.println("输出email:" + res.getString("email"));
                System.out.println("输出birthday:" + res.getString("birthday"));
                System.out.println("****************************");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            Test02.getReales(con,sta,res);
        }
    }
}

2.4 PreparedStatement对象

PreparedStatement是Statement的子接口,用于执行预编译的SQL语句。该接口扩展了带有参数SQL语句的执行操作,应用该接口中的SQL语句可以使用占位符“?”来代替其参数,然后通过setXxx()方法为SQL语句的参数赋值。

使用PreparedStatement对象可以解决SQL注入不安全的问题。

  • 防止SQL注入的本质,把传递进来的参数当作字符;
  • 如果其中存在转义字符,则会自动转义;
	public class TestPreparedInto {
    public static void main(String[] args) {
//        login("zhansan","123456");
        login("''or 1=1","123456");     //SQL注入问题被解决
    }

    public static void login(String username,String password){
        Connection con = null;
        PreparedStatement pstm = null;
        ResultSet res = null;

        try {
            con = JdbcUtils.getConnection();
            String sql = "select * from users where name=? and password=?";
            pstm = con.prepareStatement(sql);
            pstm.setString(1,username);
            pstm.setString(2,password);

            res = pstm.executeQuery();
            while (res.next()){
                System.out.println(res.getString("name"));
                System.out.println(res.getString("password"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(con,pstm,res);
        }
    }
}

增删改方法:

//添加操作:
public class TestInsert{
    Connection con = null;
    PreparedStatement pstm = null;
    
    try{
        con = jdbc.getConnection();
        //与Statement的区别:无createStatement,且需要传入sql值;
        //sql语句中可以使用 ? 占位符:
        String sql = "insert into users(id,NAME,PASSWORD,email,birthday) values(?,?,?,?,?)";
        pstm = con.preparedStatement(sql);
        //手动给sql语句中?占位符赋值:(第一个问号的位置,具体值)
         pstm.setInt(1,4);   
         pstm.setString(2,"VXXL");
         pstm.setString(3,"123456");
         pstm.setString(4,"721321@email.com");
        //表中的setDate()方法可以设置日期内容,但参数Date的类型是java.sql.Date,而不是						  java.util.Date。
       	 pstm.setDate(5,new java.sql.Date(new Date().getTime()));
        //执行:与Statement的区别--->不用传参;
        int i = pstm.executeUpdate();
        if (i > 0){
                System.out.println("添加成功");
            }
    }catch (SQLException e) {
            e.printStackTrace();
    }finally{
        jdbc.release(con,pstm,null);
    }
}

//修改操作:
public class TestUpdate{
    Connection con = null;
    PreparedStatement = null;
    
    try{
        con = jdbc.getConnection();
        String sql = "update users set name=? where id=?";
        pstm = con.preparedStatement(sql);
        pstm.setString(1,"VX");
        pstm.setInt(2,4);
        int i = pstm.executeUpdate();
        if(i > 0){
            System.out.println("修改成功");
        }
    }catch (SQLException e) {
            e.printStackTrace();
    }finally{
        jdbc.release(con,pstm,null);
    }
}

//删除操作:
public class TestDelete{
    Connection con = null;
    PreparedStatement pstm = null;
    
    try{
        con = jdbc.getConnection();
        String sql = "delete from users where id=?";
        pstm = con.preparedStatement(sql);
        pstm.setInt(1,4);
        int i = pstm.executeUpdate();
        if(i > 0){
            System.out.println("删除成功");
        }
    }catch (SQLException e) {
            e.printStackTrace();
    }finally{
        jdbc.release(con,pstm,null);
    }
}

查询方法:

public class TestSelect{
    Connection con = null;
    PreparedStatement pstm = null;
    ResultSet res = null;
    
    try{
        con = jdbc.getConnection();
        String sql = "select * form users where name=? and password=?";
        pstm = con.preparedStatement(sql);
        pstm.setString(1,"VX");
        pstm.setString(2,"123456");
        res = pstm.executeQuery();
        while(res.next()){
            System.out.println(res.getString("name"));
            System.out.println(res.getString("password"));
        }
    }catch (SQLException e) {
            e.printStackTrace();
    }finally{
        jdbc.release(con,pstm,res);
    }
}

3、使用IDEA连接数据库

具体步骤:(社区版需要下载插件)

image-20210509225128823

image-20210509225204166

image-20210509225313799

如果连接成功,那么就可以在idea使用数据库操作了。

4、JDBC操作事务

基本操作跟mysql的事务操作一样,只不过java中Connection就相当于SQL。

public class TestTransaction {
    public static void main(String[] args) {
        Connection con = null;
        PreparedStatement pstm = null;

        try {
            con = JdbcUtils.getConnection();
            //关闭事务自动提交:
            con.setAutoCommit(false);
            //开启事务:java中默认开启事务
            String sql1 = "update account set money=money-100 where name='A'";
            pstm = con.prepareStatement(sql1);
            pstm.executeUpdate();					//提交事务

            String sql2 = "update account set money=money+100 where name='B'";
            pstm = con.prepareStatement(sql2);
            pstm.executeUpdate();					//提交事务

            con.commit();					//事务成功执行提交
            System.out.println("事务处理成功");
            con.setAutoCommit(true);
        } catch (SQLException e) {
            try {
                System.out.println("事务处理失败");
                con.rollback();				//事务失败执行回滚
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }finally {
            JdbcUtils.release(con,pstm,null);
        }
    }
}

5、DBCP-C3P0连接池

实质:编写连接池,实现一个接口DataSource

5.1 DBCP连接

需要的JAR包:commons-dbcp-1.4.jar 和 commons-pool-1.6.jar

#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=123456

#!-- 初始化连接 --
initialSize=10

#最大连接数量
maxActive=50

#!-- 最大空闲连接 --
maxIdle=20

#!-- 最小空闲连接 --
minIdle=5

#!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 --
maxWait=60000
#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:【属性名=property;】
#注意:user 与 password 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=UTF8

#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true

#driver default 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=

#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED

提取工具类:

public class JdbcUtils_DBCP {
    private static DataSource dataSource = null;

    static {
        try {
            InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
            Properties properties = new Properties();
            properties.load(in);

            //创建数据源 factory 工厂模式 --> 创建:
            dataSource = BasicDataSourceFactory.createDataSource(properties);

        } catch (Exception e) {
                e.printStackTrace();
            }
    }

    //获取连接:
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();          //从数据源中获取连接数据库
    }

    //释放资源:
    public static void release(Connection con, Statement sta, ResultSet res){
           try {
               if (con != null){
               con.close();
               }
               if (sta != null){
                   sta.close();
               }
               if (res != null){
                   res.close();
               }
           } catch (SQLException e) {
               e.printStackTrace();
           }

    }
}

测试类与前面的操作一样;

5.2 C3P0连接

需要的JAR包:c3p0-0.9.5.5.jar 和 mchange-commons-java-0.2.19.jar

//c3p0数据库的配置文件:
<?xml version=1.0 encoding=UTF-8?>
<c3p0-config>
   <!--
c3p0的缺省(默认)配置
如果在代码中ComboPooledDataSource ds=new ComboPooledDataSource();这样写就表示使用的是c3p0的缺省(默认)-->
<default-config>
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&amp;characterEncoding=utf8&amp;uesSSL=false&amp;serverTimezone=UTC</property>
    <property name="user">root</property>
    <property name="password">123456</property>

    <property name="acquiredIncrement">5</property>
    <property name="initialPoolSize">10</property>
    <property name="minPoolSize">5</property>
    <property name="maxPoolSize">20</property>
</default-config>
</c3p0-config>        
  
 <!--	c3p0的缺省(默认)配置
如果在代码中ComboPooledDataSource ds=new ComboPooledDataSource("MySQL");这样写就表示使用的是c3p0的使用的name是MySQL -->

提取工具类:

public class TestC3P0 {
    public static void main(String[] args) {
        Connection con = null;
        PreparedStatement pstm = null;

        try {
            con = JdbcUtils_C3P0.getConnection();

            String sql = "insert into users (id,NAME,PASSWORD,email,birthday) values (?,?,?,?,?);";
            pstm = con.prepareStatement(sql);
            pstm.setInt(1,6);
            pstm.setString(2,"VXXLL");
            pstm.setString(3,"123456");
            pstm.setString(4,"8273682@email.com");
            pstm.setDate(5,new java.sql.Date(new Date().getTime()));
            int i = pstm.executeUpdate();
            if (i > 0){
                System.out.println("添加成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

测试类与前面的操作一样;

总结:无论你使用什么数据源,其本质都是一样的,都是实现DataSource接口,都是Connection方法;

posted @ 2021-05-25 01:12  VXZX  阅读(348)  评论(0)    收藏  举报