Mysql4jdbc:事务,登陆案例,预编译,连接池

Posted 码农编程录

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mysql4jdbc:事务,登陆案例,预编译,连接池相关的知识,希望对你有一定的参考价值。


1.JDBC事务操作:conn.setAutoCommit(false)

package com.itheima01.transaction;
import com.itheima.utils.JdbcUtil;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
// JDBC : 写一个转账案例
public class Demo {
    public static void main(String[] args)  {       
        System.out.println("请输入转出的账户:"); 
        Scanner sc = new Scanner(System.in); // 控制台: 模拟页面
        String outUser = sc.nextLine();
                
        System.out.println("请输入转入的账户:");
        String inUser = sc.nextLine();   
             
        System.out.println("请输入转账的金额:");
        double money = sc.nextDouble();
        
       //sql里面最好写单引号 , 1000和jack改为 两个双引和两个+号
       //String sql1 = "update account set money = money-1000 where name = 'jack'";
        String sql1 = "update account set money = money-"+money+" where name = '"+outUser+"'";
        String sql2 = "update account set money = money+"+money+" where name = '"+inUser+"'";

//11111111111111111111111111111111111111111111111111111111111111111111111111111111111111
        Connection conn = null;
        try {
                /*
                *   事务操作: Connection
                *       1. setAutoCommit(false); 开启事务
                *       2. commit(); 提交事务
                *       3. rollback(); 事务回滚
                *   注意点: 在事务中, 开启事务的连接才具有手动提交事务的功能
                *           一组操作都必须要同一个 连接conn  要执行
                */            
            conn = JdbcUtil.getConnection(); //访问数据库,try外面定义conn
 		   // Connection conn2 = JdbcUtil.getConnection();      		        
            conn.setAutoCommit(false); //开启事务,禁止自动提交  
                          
            Statement statement = conn.createStatement(); //转出
            statement.executeUpdate(sql1);                        
            // int i = 1/0;  // ArithmeticException 算术异常 模拟银行爆炸                
            Statement statement2 = conn.createStatement(); //转入
            statement2.executeUpdate(sql2);

//1111111111111111111111111111111111111111111111111111111111111111111111111111111111111                  			
            conn.commit(); //提交事务(和事务回滚只有其一执行) 
            System.out.println("转账成功~~");
        } catch (Exception e) { // 注意: 提升异常级别(用于捕获算术异常)
            e.printStackTrace();
            if(conn != null){ //Connection conn放外面,这边访问的到
                try {
                    conn.rollback(); //事务回滚
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
            }
            System.out.println("转账失败");
        }
    }
}

在这里插入图片描述
在这里插入图片描述

2.登陆案例: ’ " +name+ " ’

在这里插入图片描述

package com.itheima02.login;
import com.itheima.utils.JdbcUtil;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
/*
    前提: 用户能够登录,说明已经注册过了
         注册成功的时候, 程序会把用户的信息保存到数据库
        
*   登录案例:
*       逻辑: 请输入用户名和密码(用户)
*       我们: 校验数据库
*       sql :  select * from account where name = ? and pwd = ?; (name用户名唯一)
*           预测结果:
*               1. 0条 : 用户名不存在或密码错误
*               2. 1条 : 登录成功
*/
public class LoginDemo {
    public static void main(String[] args) throws SQLException {
        System.out.println("请输入用户名:");
        Scanner sc = new Scanner(System.in);
        String name = sc.nextLine();  
              
        System.out.println("请输入密码:");
        String pwd = sc.nextLine();
        
        String sql = "select * from account where name = '"+name+"' and pwd = '"+pwd+"'";
        System.out.println(sql); //将参数(上面键盘输入)直接拼接进sql
        
//1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
        Connection conn = JdbcUtil.getConnection();
        Statement statement = conn.createStatement();           
        ResultSet resultSet = statement.executeQuery(sql); //将sql发送给数据库去处理
        if(resultSet.next()){ //有一条则为true
            System.out.println("登录成功~~");
        }else{
            System.out.println("用户名不存在或密码错误");
        }
    }
}

根据(用户名和密码)或(1=1永真)为条件查询数据库,what可以随便写。
在这里插入图片描述

3.登陆案例的预编译改造:PreparedStatement,setString,executeQuery

预编译知道了sql的语法结构了,已经把关键字认全了,后面再包含关键字or就不认了(当成字符串处理),可以防止sql注入
在这里插入图片描述

package com.itheima02.login;
import com.itheima.utils.JdbcUtil;
import java.sql.*;
import java.util.Scanner;

public class LoginDemo02 {
    public static void main(String[] args) throws SQLException {
        System.out.println("请输入用户名:");
        Scanner sc = new Scanner(System.in);
        String name = sc.nextLine();
        
        System.out.println("请输入密码:");
        String pwd = sc.nextLine();

            // 1. 改造sql       
        String sql = "select * from account where name = ? and pwd = ?";
        System.out.println(sql);
        Connection conn = JdbcUtil.getConnection();

           // 2. 预编译sql   // PreparedStatement 是 Statement的子接口
        PreparedStatement statement = conn.prepareStatement(sql);
            
          // 3. 设置参数
          // setString(int parameterIndex, String x)
          // parameterIndex : sql中的?的索引(从1开始,从左开始)  // String x: 参数
        statement.setString(1,name);
        statement.setString(2,pwd);

          // 4. 传参执行
        ResultSet resultSet = statement.executeQuery();
        if(resultSet.next()){
            System.out.println("登录成功~~");
        }else{
            System.out.println("用户名不存在或密码错误");
        }
    }
}

在这里插入图片描述
如下手动在数据库中增加一行
在这里插入图片描述
在这里插入图片描述

package com.itheima03.prepare;
import com.itheima.utils.JdbcUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
/*
*   预编译的好处:  1. 防止sql注入
*                 2. 阅读性强(sql)
*                 3. 批量处理sql,效率高 (节省了sql重复编译过程)
*/
public class PrepareDemo {
    public static void main(String[] args) throws SQLException {
//        method01(); //用预编译,如下不用预编译
        String name = "ww";
        int money = 200;
        String sql1 = "insert into account values(null,'"+name+"',"+money+",null)";
        
        String name2 = "www";
        int money2 = 2002;
        String sql2 = "insert into account values(null,'"+name2+"',"+money2+",null)";     
                           
        Connection conn = JdbcUtil.getConnection();
        Statement statement = conn.createStatement(); //不用预编译
        statement.executeUpdate(sql1);// 编译+运行
        statement.executeUpdate(sql2);//编译+运行,和上行一共两次编译        
        statement.close();
        conn.close();
    }

//1111111111111111111111111111111111111111111111111111111111111111111111111
    private static void method01() throws SQLException {
        String sql = "insert into account values(null,?,?,null)";        
        Connection conn = JdbcUtil.getConnection();
        PreparedStatement pstm = conn.prepareStatement(sql);   
              
        pstm.setString(1,"zs");
        pstm.setDouble(2,1000);
        pstm.executeUpdate();//运行
        
        pstm.setString(1,"ls");
        pstm.setDouble(2,2000);
        pstm.executeUpdate();//运行        
        pstm.close();
        conn.close();
    }
}

4.c3p0连接池:自动cpds.set

jdbc2.0才引进连接池,不是线程池(连接池的技术标准就是DataSource替代DriverManager)。
在这里插入图片描述

package com.itheima04.c3p0;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class C3p0Demo {  
    public static void main(String[] args) throws PropertyVetoException, SQLException {
//        method01(); //这行方法和下面xml文件无关
        /*
        * 配置文件方式 :
        *    默认情况下, c3p0将会在 类加载器路径(在当前的工程下, src路径)下
        *    寻找一个名为c3p0-config.xml 配置文件(xml文件是复杂的Properties文件,也是key-value)
        * 
        *   套路:
        *       1. 在src下创建名为c3p0-config.xml配置文件(内容直接复制)
        *       2. 创建ComboPooledDataSource核心类      
        */
        ComboPooledDataSource cpds = new ComboPooledDataSource(); 
    //1. 底层自动会去类加载器路径(写代码:src下) 去寻找一个名为c3p0-config.xml 配置文件
   // 2. 自动解析: 读取xml中配置信息 , 设置给c3p0即cpds    
             
        String sql = "select * from account";  // 同下面              
        Connection conn = cpds.getConnection();  
        PreparedStatement pstm = conn.prepareStatement(sql);
        ResultSet resultSet = pstm.executeQuery();
        while(resultSet.next()){
            String name = resultSet.getString("name");
            System.out.println(name + "--");
        }
        conn.close();// 将连接还给连接池
        cpds.close(); // 销毁
    }

//111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    private static void method01() throws PropertyVetoException, SQLException {
        // 如下硬编码: 用代码来实现参数的设置。一般不用硬编码,用配置文件
        ComboPooledDataSource cpds = new ComboPooledDataSource();//ComboPooledDataSource是DataSource实现类
        cpds.setDriverClass( "com.mysql.jdbc.Driver"); //需要mysql-connector-java-x.x.x-bin.jar
        cpds.setJdbcUrl( "jdbc:mysql://localhost:3306/day05" );
        cpds.setUser("root");
        cpds.setPassword("1234");
        
        String sql = "select * from account";              
        Connection conn = cpds.getConnection();   
        PreparedStatement pstm = conn.prepareStatement(sql);
        ResultSet resultSet = pstm.executeQuery();
        while(resultSet.next()){
            String name = resultSet.getString("name");
            System.out.println(name); //System.err.println(name);//红色
        }
        conn.close();// 将连接还给连接池
        cpds.close(); // 销毁
    }
}
//c3p0-config.xml
<c3p0-config>
    <!-- 使用默认的配置读取连接池对象 -->
    <default-config>
        <!--  连接参数 --> 
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/day05</property>
        <property name="user">root</property>
        <property name="password">1234</property>
        <!-- 连接池参数 -->
        <!--
            initialPoolSize : 初始化连接数  3
            maxPoolSize: 最大连接数  5
            checkoutTimeout : 连接超时时间 2000ms(默认10s,访问数超过最大连接数, 有人必须要等,2秒连不上给个提示或报错)                        
            maxIdleTime :最大的闲置时间,连接超过maxIdleTime没人使用闲置就销毁maxPoolSize中连接,留到minPoolSize中数量,因为费内存
        -->
        <property name="initialPoolSize">3</property>
        <property name="maxPoolSize">5</property>
        <property name="minPoolSize">2</property>
        <property name="checkoutTimeout">2000</property>
        <property name="maxIdleTime">1000</property>
    </default-config>


    <named-config name="xx">
        <!--  连接参数 -->
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/beitai</property>
        <property name="user">root</property>
        <property name="password">root</property>
        <!-- 连接池参数 -->
        <property name="initialPoolSize">5</property>
        <property name="maxPoolSize">15</property>
        <property name="checkoutTimeout">2000</property>
        <property name="maxIdleTime">1000</property>
    </named-config>
</c3p0-config>

5.类加载器路径:is = classLoader.getResourceAsStream()

package com.itheima04.c3p0;
import org.junit.Test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class ParseDemo {
    @Test
    public void method01() throws IOException {
        Properties p = new Properties(); //Properties就是一个map            
        p.load(new FileInputStream("src/jdbc.properties")); //相对路径:当前工程src下
        String url = p.getProperty("url"); //.properties文件中有url=...
        System.out.println(url);
    }    
        
    @Test
    public void method02() throws IOException {
        /*
        *     1. 类加载器 classloader 【底层: 输入流】
        *  作用: 将 .class文件(硬盘) 加载进内存(兼职把jdbc.properties加载进来)。
        * 
        *     2. classloader怎么知道.class文件在哪里?
        *  classloader有个默认加载路径:out路径下项目名路径(src和out/production/项目名路径里文件全一样)。
        * 
        *  相比method01,一般用method02更通用,因为每个工程都会有类加载器路径,但是每个工程的相对路径不一定是当前工程src下。
        *  如web阶段main方法不在项目里,每个项目的入口是main方法,main方法在tomcat里,
        *  所以工程的相对路径会变,但是类加载器的路径不变,一直指向.class文件路径。
        */
        ClassLoader classLoader = ParseDemo.class.以上是关于Mysql4jdbc:事务,登陆案例,预编译,连接池的主要内容,如果未能解决你的问题,请参考以下文章

Java学习总结(十九)——JDBC操作数据库,预编译的使用,事务,常见的连接池

sql注入,预编译和事务

什么是AOP

LLVM 预编译连接问题

mysql里面没有预编译的概念?

JDBC java数据连接 读取properties 数据库连接池 预编译