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:事务,登陆案例,预编译,连接池的主要内容,如果未能解决你的问题,请参考以下文章