jdbc(MySQL)
JDBC
- WHAT? 用于执行 SQL 语句的 Java API
- WHY? 不需要了解每一种数据库连接操作方式
- HOW? 加载驱动、获取连接、执行操作、关闭连接
1.连接数据库
1.1.连接到数据库
- 连接数据库步骤:加载驱动、获取连接、基本操作(执行SQL)、释放资源
- 连接 MySQL 数据库:
- Class.forName("com.mysql.jdbc.Driver")
- DriverManager.getConnection(url + db, username, password)
示例:获取数据库连接
// 加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 获得连接
String db = "/argor"; // 数据库名
String url = "jdbc:mysql://localhost:3305"; // url地址
String username = "argor"; // 用户名
String password = "argor"; // 密码
Connection conn = DriverManager.getConnection(url + db, username, password);
1.2.执行 SQL 语句
- SQL 语句,从编译的时机可以分为两类:静态SQL、动态SQL
- 静态SQL,编译时已经确定了引用的表和列(语句执行前已经编译过)
- 动态SQL,语句执行时才进行编译和确定表和列
- 创建SQL 语句对象(可执行对象),通过连接提供的方法获取
- createStatement(),用于执行 静态SQL 语句,创建一个 Statement 对象将 SQL 语句发送到数据库。
- prepareStatement(String sql),sql 是一个可以包含参数占位符的 SQL 语句。
- prepareCall(String sql),执行存储过程
- 执行SQL语句
- executeUpdate(String sql),DML语句(uid)返回 行计数、不返回任何内容的sql语句执行后返回 0
- executeQuery(String sql),返回 ResultSet 对象
示例:查询表
// 基本SQL语句
Statement sm = conn.createStatement(); // 获取SQL语句对象
String sql = "select * from t_users";
ResultSet rs = sm.executeQuery(sql); // 执行查询操作
1.3.处理执行结果
- 接口 ResultSet,表示 通过执行查询数据库语句获取到的结果。
- 遍历 ResultSet 结果集
- 遍历条件:boolean next(),新的当前行有效,返回 true
- 遍历方法:getXXX 方法
- String getString(int 列序号)
- String getString(String 列名)
示例:遍历查询结果
ResultSet rs = sm.executeQuery(sql); // 执行查询操作
while(rs.next()){
System.out.print(rs.getString("id") + " ");
System.out.println(rs.getString("logname"));
}
1.4.回收资源
示例:
package com.mysql.jdbc; import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Connection;
import java.sql.ResultSet; public class Demo4 {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} //加载驱动结束 //监听在3305,密码为空
String url = "jdbc:mysql://localhost:3305/web_test3?user=root&password=";
String sql = "SELECT * FROM user"; Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection(url);
stmt = conn.createStatement();
rs = stmt.executeQuery(sql); if (stmt.execute(sql)) {
rs = stmt.getResultSet();
} // Now do something with the ResultSet ....
while (rs.next()) {
System.out.print(rs.getString("id") + ", ");
System.out.print(rs.getString("username") + ", ");
System.out.print(rs.getString("password") + ", ");
System.out.print(rs.getString("nickname") + ", ");
System.out.println(rs.getString("age"));
}
} catch (SQLException ex) {
// handle any errors
System.out.println("SQLException: " + ex.getMessage());
System.out.println("SQLState: " + ex.getSQLState());
System.out.println("VendorError: " + ex.getErrorCode());
} finally {
// It is a good idea to release resources in a finally{} block.
// In reverse-order of their creation if they are no-longer needed. if (rs != null) {
try {
rs.close();
} catch (SQLException sqlEx) {} // ignore
rs = null;
} if (stmt != null) {
try {
stmt.close();
} catch (SQLException sqlEx) {} // ignore
stmt = null;
} if (conn != null) {
try {
conn.close();
} catch (SQLException e){} // ignore
conn = null;
}
}
}
}
1.5.实现工具类
- 工具类 Demo5,实现 数据库的 uid 操作。
示例: 包含增加行,查询。使用时需要 new,传入需要执行的 sql (URL),调用 doSelect(),doInsert() 即可。
package com.mysql.jdbc; import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Connection; /*
* DML uid 操作抽取成方法
*/
public class Demo5 {
protected String url = "jdbc:mysql://:3305/web_test3?user=root&password=";
protected Connection conn = null;
protected String sql = null;
protected Statement stmt = null; /**
* 构造方法
* @param sql
*/
public Demo5(String sql) {
setSql(sql);
stmt = getStatement();
} public Demo5(String sql, String url) {
setSql(sql);
setUrl(url);
stmt = getStatement();
} /**
* 插入数据 (子类继承,使用 PrepareStatement 时重写)
*/
public void doInsert(){
int i = -1;
try {
i = stmt.executeUpdate(sql);
} catch (SQLException e) {
e.printStackTrace();
} System.out.println(i);
} /**
* 查询操作 (子类继承,使用 PrepareStatement 时重写)
* @param stmt
* @param sql
* @return
*/
public ResultSet doSelect() {
try {
return stmt.executeQuery(sql);
} catch (SQLException e) {
e.printStackTrace();
} return null;
} /**
* 执行静态 SQL 语句并返回结果对象 (子类继承,使用 PrepareStatement 时重写)
* @param conn
* @return
*/
public Statement getStatement() {
conn = getConnection();
try {
return conn.createStatement(); //构造方法中赋值给 stmt
} catch (SQLException e) {
e.printStackTrace();
} return null;
} /**
* 创建 MySQL 数据库连接
* @param url 数据库地址
* @return 数据库连接
*/
public Connection getConnection() {
wakeUpMySQL();
try {
return DriverManager.getConnection(url);
} catch (SQLException e) {
e.printStackTrace();
} return null;
} /**
* 加载驱动,唤醒 MySQL
*/
public void wakeUpMySQL() {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} /**
* 释放资源
* @param rs 结果集
*/
public void release(ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException sqlEx) {
} // ignore
rs = null;
}
} public void release(Statement stmt) {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException sqlEx) {
} // ignore
stmt = null;
}
} public void release(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
} // ignore
conn = null;
}
} /**
* 设定 SQL 语句
* @param sql
*/
public void setSql(String sql) {
this.sql = sql;
} public void setUrl(String url) {
this.url = url;
} }
示例:查询
String sql = "select * from user";
Demo5 mysql = new Demo5(sql);
ResultSet rs = mysql.doSelect();
select
示例:插入
String sql = "insert into user values (null, 'eee', '123','小强',19)";
Demo5 mysql = new Demo5(sql, "jdbc:mysql://:3305/web_test3?user=root&password=");
mysql.doInsert();
insert
示例:增加 删除、修改功能
class Mysql extends Demo5 { public Mysql(String sql, String url) {
super(sql, url);
}
public Mysql(String sql) {
super(sql);
} public void doUpdate() {
super.doInsert();
} public void dodelete() {
super.doInsert();
}
}
Mysql mysql = new Mysql("delete from user where id = 8");
mysql.dodelete();
Mysql mysql = new Mysql("update user set password = \"456\" where id = 1");
mysql.doUpdate();
1.6.重写工具类
- PrepareStatement 使用格式:从实现SQL操作实例,对比上边的使用格式。
示例: 查询,?出现的位置(出现在列名、表名时报错)
String sql = "select username,nickname from user where username = ?"; //SQL 书写存在差异
PreparedStatement pstmt = conn.prepareStatement(sql); //获取执行语句 存在差异
pstmt.setString(1, "ccc"); ResultSet rs = pstmt.executeQuery(); //执行方法一致
示例: 插入,?出现的位置(出现在表名 时报错)
String sql = "insert into user values (null, ?, ?, ?, ?);";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "eee");
pstmt.setString(2, "123");
pstmt.setString(3, "小强");
pstmt.setString(4, "19"); pstmt.executeUpdate();
示例: 修改,?出现的位置
String sql = "update user set username = ?, password = ?, age = ? where id = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "fff");
pstmt.setString(2, "342");
pstmt.setString(3, "33");
pstmt.setString(4, "7"); pstmt.executeUpdate();
示例: 删除,?出现的位置
String sql = "delete from user where username = ? and age = ? and id = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "fff");
pstmt.setString(2, "33");
pstmt.setString(3, "7"); pstmt.executeUpdate();
- 使用工具类实现 CRUD
- 使用接口 PrepareStatement 替换工具类功能,实现工具类 Pdemo1。
工具类的实现,继承了上边 Demo5。
package com.mysql.jdbc; import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.ResultSet; public class Pdemo1 extends Demo5 {
private PreparedStatement pstmt = null; /*
* 构造
*/
public Pdemo1(String sql) {
super(sql);
pstmt = getStatement();
} /*
* 构造
*/
public Pdemo1(String sql, String url) {
super(sql, url);
pstmt = getStatement();
} public void setPstmtString(int i, String s) {
try {
pstmt.setString(i, s);
} catch (SQLException e) {
e.printStackTrace();
}
} public void doUpdate() {
this.doInsert();
} public void doDelete() {
this.doInsert();
} @Override
public void doInsert() {
int i = -1;
try {
i = pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} System.out.println(i);
} @Override
public ResultSet doSelect() {
try {
return pstmt.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
} return null;
} @Override
public PreparedStatement getStatement() {
conn = super.getConnection();
try {
return conn.prepareStatement(sql);
} catch (SQLException e) {
e.printStackTrace();
} return null;
}
}
示例:查询
Pdemo1 pmysql = new Pdemo1("select username, nickname, age from user where id = ?");
pmysql.setPstmtString(1, "6");
ResultSet rs = pmysql.doSelect(); try {
while (rs.next()) {
System.out.print(rs.getString("username") + ", ");
System.out.print(rs.getString("nickname") + ", ");
System.out.println(rs.getString("age"));
}
} catch (SQLException e) {
e.printStackTrace();
}
示例:插入
Pdemo1 pmysql = new Pdemo1("insert into user values (null, ?, ?, ?, ?);");
pmysql.setPstmtString(1, "fff");
pmysql.setPstmtString(2, "1232");
pmysql.setPstmtString(3, "小宁");
pmysql.setPstmtString(4, "29");
pmysql.doInsert();
示例:修改
Pdemo1 pmysql = new Pdemo1("update user set username = ?, password = ?, age = ? where id = ?");
pmysql.setPstmtString(1, "ggg");
pmysql.setPstmtString(2, "1192");
pmysql.setPstmtString(3, "31");
pmysql.setPstmtString(4, "8");
pmysql.doUpdate();
示例:删除
Pdemo1 pmysql = new Pdemo1("delete from user where id = ?", "jdbc:mysql://:3305/web_test3?user=root&password=");
pmysql.setPstmtString(1, "6");
pmysql.doDelete();
1.7.JDBC 的批处理
- JDBC 批处理基本操作(Statement)
/*
* 批处理操作流程
*/
public class Bdemo1 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://:3305/web_test3?user=root&password=");
String[] sqls = { "insert into user values (null, 'H', '123','小丽',134)",
"insert into user values (null, 'I', '123','小王',132)",
"insert into user values (null, 'J', '123','小明',128)",
"insert into user values (null, 'K', '123','大黄',121)" };
String tmp = "show tables"; //这行内容不管是什么(合法SQL),都不会因为调用 executeBatch() 而执行
PreparedStatement pstmt = conn.prepareStatement(tmp);
pstmt.clearBatch();
for (String sql : sqls) {
pstmt.addBatch(sql);
} pstmt.executeBatch(); // 只会执行 addBatch(sql) 传入的 SQL 语句
conn.close();
}
}
- 工具类实现 SQL 的 UID 操作
实例:创建子类实现批处理,完成 UID 操作
package com.mysql.jdbc.batch; import java.sql.ResultSet;
import java.sql.SQLException; import com.mysql.jdbc.Pdemo1; public class PBDemo1 extends Pdemo1{
/*
* 构造方法 增加功能,实现批量执行
*/
public PBDemo1(String[] sql) throws SQLException {
super(sql[0]); //调用父类构造,传入第一条SQL,没有调用相应方法,该SQL语句没有执行,仅仅是调用了一次父类构造
pstmt.clearBatch();
for (int i = 0; i<sql.length; i++) {
pstmt.addBatch(sql[i]); //父类成员变量 pstmt 的类型,从 private 修改成 protected
}
}
public PBDemo1(String[] sql, String url) throws SQLException {
this(sql); //调用
setUrl(url); //调用父类方法(本身就是 public 类型的)
} @Override
public void doInsert() {
doSQL();
}
@Override
public void doUpdate() {
doSQL();
}
@Override
public void doDelete() {
doSQL();
}
/*
* 调用 executeBatch,执行 SQL 语句
*/
public void doSQL() {
int sum = 0;
int[] resultExeSQL = null;
try {
resultExeSQL = pstmt.executeBatch();
} catch (SQLException e) {
e.printStackTrace();
} for (int j : resultExeSQL) {
sum += j;
}
System.out.println(sum);
}
}
实例:写个测试类
package com.mysql.jdbc.batch; import java.sql.SQLException; public class PBtest1 {
public static void main(String[] args) {
PBDemo1 pbmysql = null;
String[] sql = { "insert into user values (null, 'H', '123','小丽',134)",
"insert into user values (null, 'I', '123','小王',132)",
"insert into user values (null, 'J', '123','小明',128)",
"insert into user values (null, 'K', '123','大黄',121)" };
try {
pbmysql = new PBDemo1(sql);
} catch (SQLException e) {
e.printStackTrace();
} pbmysql.doInsert();
}
}
2.配置文件
示例:配置文件示例:
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3305/argor
user=argor
pwd=argor
示例:读取配置的方法:
Properties properties = new Properties();
properties.load(new FileInputStream("conf\\db.properties"));
String driverClassName = properties.getProperty("driverClassName");
String url = properties.getProperty("url");
String user = properties.getProperty("user");
String pwd = properties.getProperty("pwd");
示例:使用配置文件访问数据库(使用 prepareStatement 对象查询数据库)
Class.forName(driverClassName);
Connection conn = DriverManager.getConnection(url, user, pwd); String sql = "select usernae,nickname from t_users where id > ? and id < ?";
PreparedStatement psm = conn.prepareStatement(sql);
psm.setString(1, "700");
psm.setString(2, "1230");
ResultSet rs = psm.executeQuery();
3.连接池
- 原理:将数据库连接作为对象存放在内存中,实现数据库连接的快速实现和脱离。内存中的数据库连接由使用连接业务以外的程序管理。由于避免了建立连接、销毁连接从而提高访问数据库的效率。
示例*:连接池的思想 -- 把连接保存到内存中,需要时从内存中引用即可
package com.donatello; import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List; /*
* 连接池
*/
public final class Demo1 {
protected static String url ="jdbc:mysql://:3305/web_test3?user=root&password=";
protected static Connection tmp = null;
private static List<Connection> links = null;
private static int count = 50; {
links = makeConnection(count);
} public static boolean putConnection(Connection link) {
boolean flag = Demo1.links.add(link);
return flag;
} public static Connection getConnection() {
tmp = links.remove(0);
return tmp;
} private static List<Connection> makeConnection(int count) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} List<Connection> links = new ArrayList<Connection>();
for (int i=0; i<count; i++) {
try {
links.add(DriverManager.getConnection(url));
} catch (SQLException e) {
e.printStackTrace();
}
} return links;
}
}
3.1.druid
示例: 连接池启用步骤:
DruidDataSource dataSource = new DruidDataSource();
// dataSource.setDriverClassName("com.mysql.jdbc.Driver"); //注释了也不影响(免驱动)
String jdbcUrl = "jdbc:mysql://:3305/web_test3?user=root&password=";
dataSource.setUrl(jdbcUrl);
// dataSource.setUsername("root");
// dataSource.setPassword("");
DruidPooledConnection conn = dataSource.getConnection(); SleepMoment.waitMe(30); // 程序停滞30秒
示例:druid.properties 配置文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://:3305/argor
username=argor
password=argor
示例:druid.properties配置文件(可以配置多个连接目标)
url=jdbc:mysql://:3305/argor?user=argor&password=argor
实现代码:使用配置文件获取信息,启用 Druid
Properties proFile = new Properties();
proFile.load(new FileInputStream("conf/druid.properties"));
DataSource datasource = DruidDataSourceFactory.createDataSource(proFile);
Connection conn = datasource.getConnection(); SleepMoment.waitMe(30); // 程序停滞30秒
示例:工具类(这个可以使用红色星号代码思想重写,因为代码执行时只有一个到数据库的连接)
package argor.jdbc.mysql; import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties; import javax.sql.DataSource; import com.alibaba.druid.pool.DruidDataSourceFactory; public class JDBCUtils_druid {
private static DataSource ds = null; static {
final Properties prop = new Properties();
try {
prop.load(new FileInputStream("conf/druid.properties"));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
ds = DruidDataSourceFactory.createDataSource(prop);
} catch (Exception e) {
e.printStackTrace();
}
} // static{} over. public static Connection getConnection() {
try {
return ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
} public static DataSource getDataSource() {
return ds;
}
}
测试代码:
Connection conn = JDBCUtils_druid.getConnection(); /*
* 程序停滞30秒,每秒输出一个句点到控制台。
* 让程序停滞的目的,是到数据库上查看目前数据库中接入的连接。
*/
SleepMoment.waitMe(30);
3.2.c3p0
- 同时导入两个包: lib/c3p0-0.9.5.2.jar、lib/mchange-commons-java-0.2.11.jar
示例:使用步骤
ComboPooledDataSource cs = new ComboPooledDataSource();
cs.setDriverClass( "com.mysql.jdbc.Driver" ); //loads the jdbc driver
cs.setJdbcUrl( "jdbc:mysql://:3305/argor" );
cs.setUser("argor");
cs.setPassword("argor"); Connection conn = cs.getConnection();
示例: c3p0-config.xml 配置文件(初始3个连接)
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://:3305/web_test3</property>
<property name="user">root</property>
<property name="password"></property>
</default-config>
</c3p0-config>
示例: c3p0-config.xml 配置文件(初始10个连接)
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="automaticTestTable">con_test</property>
<property name="checkoutTimeout">30000</property>
<property name="idleConnectionTestPeriod">30</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
</default-config> <!-- Connect to MySQL DataBase. -->
<named-config name="MySQL">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://:3305/web_test3</property>
<property name="user">root</property>
<property name="password"></property>
</named-config>
</c3p0-config>
测试代码:启用 c3p0,连接数据库
// ComboPooledDataSource dataSource = new ComboPooledDataSource(); //没有参数,获取的是默认目标
ComboPooledDataSource dataSource = new ComboPooledDataSource("MySQL"); //非默认目标
Connection conn = dataSource.getConnection(); SleepMoment.waitMe(30); // 程序停滞30秒,测试数据库连接状态
示例:工具类(连接池可以通过配置文件控制)
package argor.jdbc.mysql; import java.sql.Connection;
import java.sql.SQLException; import javax.sql.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; public class JDBCUtils {
private static final ComboPooledDataSource ds = new ComboPooledDataSource("MySQL"); /**
* 获取一个MySQL数据库连接
* @return
*/
public static Connection getConnection() {
try {
return ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
} public static DataSource getDataSource() {
return ds;
} }
测试类:
Connection conn = JDBCUtils.getConnection(); SleepMoment.waitMe(30);
3.3.commons-dbutils
- Apache 提供维护
- 使用方法:
- 非事务操作 -> 不需要获取连接,就可以直接执行 suid 操作(CRUD)。
- 事务操作 -> 要求在一个连接下进行,就需要获取某个 连接。
格式 |
说明 |
|
构造 | QueryRunner() | 方法调用需要指定 conn |
QueryRunner(DataSource ds) | 无须指定 conn,自动处理 | |
方法 | int update(String sql, ?:value, ?:value ...) | 增、删、改的 SQL 操作 |
int update(Connection conn, String sql, ?:value, ?:value ...) | 返回值:影响的行数 | |
<T> T query(String sql, ResultSetHandler<T> rsh, Object... params) | 执行查询,返回结果, | |
<T> T query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params) | ||
int[] batch(Connection conn, String sql, Object[][] params) | ||
int[] batch(String sql, Object[][] params) |
-----------
- 结果集 ResultSetHandler,是个接口。有多个实现类
ArrayHandler,一条记录封装到一个数组中
ArrayListHandler,多条记录封装到一个数组集合中
BeanHandler,一条记录封装到一个 JavaBean 中
BeanListHandler,多条记录封装到 JavaBean 集合中
MapHandler,封装一条记录到 Map 集合,以字段名作为 key,记录属性作为 Value。
MapListHandler,封装过 Map 的 List 集合…… ColumnListHandler,查询一列
ScalarHandler,返回结果是个单值
示例:获取查询结果,对结果进行封装
new JDBCUtils_c3p0("test");
QueryRunner qr = new QueryRunner(JDBCUtils_c3p0.getDataSource()); String sql1 = "select * from http where id = ?";
String sql2 = "select * from http"; Object[] result = qr.query(sql1, new ArrayHandler(), 3);
List<Object[]> result = qr.query(sql2, new ArrayListHandler());
Map<String, Object> result = qr.query(sql1, new MapHandler(), 7);
List<Map<String, Object>> result = qr.query(sql2, new MapListHandler());
Web result = qr.query(sql1, new BeanHandler<Web>(Web.class), 9);
List<Web> result = qr.query(sql2, new BeanListHandler<Web>(Web.class));
示例:只查询 “一列”
new JDBCUtils_c3p0("test");
QueryRunner qr = new QueryRunner(JDBCUtils_c3p0.getDataSource()); // 只查询一列数据
String sql = "select name from http";
List<Object> list = qr.query(sql, new ColumnListHandler<>("name"));
示例:查询的结果是个单值
String sql = "select user()";
Object obj = qr.query(sql, new ScalarHandler<>());
- 类 DbUtils
格式 |
说明 |
Static void CommitAndCloseQuietly(Connection conn) | |
Static void RollbackAndCloseQuietly(Connection conn) | 回滚、关闭 conn,处理可能的 SQLExceptions |
4.事务
什么是事务?一元九个
- 逻辑上相关的一组操作,任意一个操作失败,其他操作都会失去意义。
事务的四大特性(ACID):事务结果 = 操作1(结果:false | true) && 操作2 && ...
- 原子性 A,
- 一致性 C,
- 隔离性 I ,
- 持久性 D,
事务的隔离级别:
- READ_UNCOMMITED,读未提交
- READ_COMMITED,读已提交
- REPEATABLE_READ,重复读
- SERIALIZABLE,串行读
MySQL 的事务管理:事务默认自动提交
- 手动开启事务
- 设置自动提交参数
示例:查看 MySQL 的事务默认设置
mysql> show variables like "%commit%";
+--------------------------------+-------+
| Variable_name | Value |
+--------------------------------+-------+
| autocommit | ON |
| innodb_commit_concurrency | 0 |
| innodb_flush_log_at_trx_commit | 1 |
+--------------------------------+-------+
3 rows in set (0.00 sec)
示例:修改自动提交(服务重启失效)
mysql> set autocommit=off;
Query OK, 0 rows affected (0.00 sec)
示例:手动开启事务(结束事务,还可以使用 rollback 代替 commit)
mysql> start transaction;
mysql> insert into ...
mysql> insert into ...
mysql> update table ...
mysql> update table ...
mysql> commit
Java代码中的事务
事务须加在业务层,事务中的 dao 操作使用同一个 Connection。
示例:事务管理,在业务层获得 Connection,以参数形式传递
//添加事务管理
public int doTransactionTranfer(Transfer transfer) throws SQLException {
Connection conn = JDBCUtils_c3p0.getConnection();//获取 Connection
conn.setAutoCommit(false);//启动事务 - 关闭自动提交
UpdateAccountInfo updateAccountInfo = new UpdateAccountInfo();
int result = updateAccountInfo.doTransactionTransfer(conn, transfer);//传入 Connection
if (result == 2) {
System.out.println("service's commit.");
conn.commit();//提交
} else {
conn.rollback();//回滚
System.out.println("service's rollback.");
} conn.close();
System.out.println("service's return: " + result);
return result;
}
在 service 层,绑定 Connection 到“当前线程”。
示例:事务管理,本地线程保存 Connection,dao 层从线程中获取
//添加事务管理
//使用本地线程控制事务
public String doTransactionTranfer2(Transfer transfer) throws SQLException {
JDBCUtils_c3p0.beginTransaction();//启动事务(关闭自动提交)
UpdateAccountInfo updateAccountInfo = new UpdateAccountInfo();
String flag = updateAccountInfo.doTransactionTransfer(transfer);//无连接 JDBCUtils_c3p0.endTransaction(flag);
System.out.println(TimeUtils.getHumanCurrentTime24() + "service's return: " + flag);
return flag;
} //dao 调用
// 转账(本地线程控制事务)
public String doTransactionTransfer(Transfer transfer) throws SQLException {
Connection conn = JDBCUtils_c3p0.getConn();//使用本地线程的 Connection
if (conn == null) {
System.out.println(TimeUtils.getTimestamp() + " hasn't Connection-Object.");
return JDBCUtils_c3p0.ROLLBACK;//零行影响
} int result = 0;
result += doReductMoney(conn, transfer);//返回值为影响的行数,期待正确值为 1。
result += doAddMoney(conn, transfer);
System.out.println(TimeUtils.getTimestamp() + "dao's doTransactionTransfer."); if (2 == result) {
return JDBCUtils_c3p0.COMMIT;
} else {
return JDBCUtils_c3p0.ROLLBACK;
}
}
JDBC 的事务管理
- 转账(代码)
A
jdbc(MySQL)的更多相关文章
- jdbc(mysql)数据库连接
0.将驱动引入项目 在项目根目录新建文件夹lib,把数据库驱动mysql-connector-java-5.1.7-bin.jar放入该文件夹. 右键点击项目名称->properties-> ...
- JDBC(MySQL)一周学习总结(一)
一周过去了,我在这分享一下这一周来学习 JDBC 的知识,同时也希望可以帮到别人! 首先我们从获取 JDBC 连接开始 Driver(每个驱动程序类必须实现的接口) 获取数据库连接需要配置数据库连接信 ...
- JDBC(MySQL)一周学习总结(二)
上一篇文章我们总结了获取数据库连接以及操作数据表的一些知识点,本篇将继续上次的文章给大家分享! 1. 上一篇文章我们可以对数据表进行增删改查的操作了,对与一些小项目的部分功能我们也足以胜任.但现在有一 ...
- 浅谈JDBC(一)
一.JDBC技术引言 1.什么是JDBC技术 提供了一套接口规范,利用java代码进行数据库操作. 2.JDBC技术的核心思想 对于程序员来说,代码访问数据库分为三个步骤:1.通过数据库的账号密码.2 ...
- 跟着刚哥学习Spring框架--JDBC(六)
Spring的JDBC框架 Spring JDBC提供了一套JDBC抽象框架,用于简化JDBC开发. Spring主要提供JDBC模板方式.关系数据库对象化方式.SimpleJdbc方式.事务管理来简 ...
- Springboot 之 Hibernate自动建表(Mysql)
Springboot 之 Hibernate自动建表(Mysql) 2016年10月21日 10:39:44 阅读数:8180 本文章来自[知识林] 引入Maven依赖包 <dependency ...
- (MySQL里的数据)通过Sqoop Import Hive 里 和 通过Sqoop Export Hive 里的数据到(MySQL)
Sqoop 可以与Hive系统结合,实现数据的导入和导出,用户需要在 sqoop-env.sh 中添加HIVE_HOME的环境变量. 具体,见我的如下博客: hadoop2.6.0(单节点)下Sqoo ...
- (MySQL里的数据)通过Sqoop Import HBase 里 和 通过Sqoop Export HBase 里的数据到(MySQL)
Sqoop 可以与HBase系统结合,实现数据的导入和导出,用户需要在 sqoop-env.sh 中添加HBASE_HOME的环境变量. 具体,见我的如下博客: hadoop2.6.0(单节点)下Sq ...
- laravel5 数据库配置(MySQL)
laravel5 数据库配置(MySQL) 首先有一个安装完成可以运行的laravel框架. 配置database.php 进入laravel根目录. 在config目录下找到database.php ...
随机推荐
- RedHat7安装vmware虚拟机启动报错
提示错误如下: Kernel Headers for version 3.10.0-229.14.1.el7.x86_64 were not found.If you.... 安装kernel dev ...
- lsof根据端口返回进程号杀死进程的方法
参考自:http://newmiracle.cn/?p=661 Linux shell根据端口返回进程号杀死进程的方法 kill -9 `lsof -t -i:8888` 这个就是杀死8888端口的进 ...
- php解析url并得到url中的参数及获取url参数
<?php $url = 'http://www.baidu.com/index.php?m=content&c=index&a=lists&catid=6&ar ...
- 【巷子】---flux---【react】
一.什么是Flux Flux 是一种架构思想,专门解决软件的结构问题.它跟MVC 架构是同一类东西,但是更加简单和清晰. 二.flux的基本概念 (1) .Flux由4部分组成 1.View:视图层 ...
- 在windows server上配置java jdk后,可能要些时间生效。
特别是程序调用java写的bat脚本时.
- js写法【3】
var m=[]; m[m.length]=xx;//相当于push 对Repeat方法提供了8种写法做比较,这一点还是不错的.
- Visual studio 下C++工程相关经验
1.链接其他库调试时产生告警: warning LNK4099: 未找到 PDB“vc100.pdb” 解决方案:属性 -> C/C++ -> 输出文件 -> 程序数据库文件名 -& ...
- 【异常处理】Springboot对Controller层方法进行统一异常处理
Controller层方法,进行统一异常处理 提供两种不同的方案,如下: 方案1:使用 @@ControllerAdvice (或@RestControllerAdvice), @ExceptionH ...
- 【剑指offer】逆序输出链表
输入一个链表,按链表值从尾到头的顺序返回一个ArrayList. *考察栈的使用 *使用循环输出Stack中内容的时候,不能使用for(int i; i<stack.size();i++)因为s ...
- 学习笔记之MobaXterm
MobaXterm free Xserver and tabbed SSH client for Windows https://mobaxterm.mobatek.net/ Enhanced ter ...