SQL语句分类
DML:操作数据库语言,就是我们常说的增删改查SELECT、UPDATE、INSERT、DELETE
DDL:数据库定义语言,主要命令有REATE、ALTER、DROP等,DDL主要是用在定义或改变表(TABLE)的结构,数据类型,表之间的链接和约束等初始化工作上
DCL:控制数据库语言。用来设置或更改数据库用户或角色权限的语句,包括(grant,deny,revoke等)语句。在默认状态下,只有sysadmin,dbcreator,db_owner或db_securityadmin等人员才有权力执行DCL
事务(Transaction)
事务开始于
连接到数据库,开始执行一条DML语句,每一条DML语句都是一个独立的事务(查询语句不是事务语句)
事务结束于
执行commit语句,rollback语句
执行一条DCL语句
执行一条DDL语句
断开了与数据库的连接
执行一条DML语句,但是失败了,执行ROOLBACK语句
事务的四大特点(ACID)
原子性:一个事务的所有SQL语句,要么全部成功,要不失败
一致性:事务中的一个操作失败,回滚
隔离性:事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要不是另一个事务修改它之后的状态,事务不会直接查看中间数据的状态
持久性:持久性事务完成之后,对于系统的影响是永久的
事务的隔离级别
未提交读(Read Uncommitted)
直译就是"读未提交",意思就是即使一个更新语句没有提交,但是别的事务可以读到这个改变。
Read Uncommitted允许脏读。
已提交读(Read Committed)
直译就是"读提交",意思就是语句提交以后,即执行了 Commit 以后别的事务就能读到这个改变,只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别。
Read Commited 不允许脏读,但会出现非重复读。
可重复读(Repeatable Read):
直译就是"可以重复读",这是说在同一个事务里面先后执行同一个查询语句的时候,得到的结果是一样的。
Repeatable Read 不允许脏读,不允许非重复读,但是会出现幻象读。
串行读(Serializable)
直译就是"序列化",意思是说这个事务执行的时候不允许别的事务并发执行。完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞。
Serializable 不允许不一致现象的出现。
JDBC是默认自动提交事务的,每一条DML语句都是一个事务,默认情况就会提交执行。那么在事务包含几个SQL语句时,先设置连接的自动提交为fasle,等事务语句执行完,进行手动提交
package xidian.lili.JDBC;
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 测试事务
*/
public class Demo06 {
public static void main(String[] args) throws InterruptedException {
PreparedStatement stmt=null;
PreparedStatement stmt2=null;
Connection con=null;
try {
Class.forName("com.mysql.jdbc.Driver");
con=DriverManager.getConnection("jdbc:mysql://localhost:3306/tsetjdbc",
"root", "123456");
con.setAutoCommit(false);//手动提交事务
String sql="insert into t_user (username,regtime,pwd) values (?,?,?);";
//事务的开始 一条DML语句
stmt=con.prepareStatement(sql);
stmt.setString(1, "王东利");
stmt.setDate(2, new java.sql.Date(System.currentTimeMillis()));
stmt.setString(3, "666666");
stmt.executeUpdate();
System.out.println("第一条插入成功");
Thread.sleep(6000);
//事务的第二条条DML语句
stmt2=con.prepareStatement(sql);
stmt2.setString(1, "王曦");
stmt2.setDate(2, new java.sql.Date(System.currentTimeMillis()));
stmt2.setString(3, "123456");
stmt2.executeUpdate();
System.out.println("第二条插入成功");
//手动提交事务,事务结束
con.commit();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
try {
con.rollback();//遇到异常就回滚
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally{
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(con!=null){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
若是事务的第二条SQL语句出现问题,则原子性,第一条也不会插入到数据库中。
java.sql.Date和java.sql.Timestamp
都是java.util.Date的子类,java.sql.Date格式是年月日,java.sql.Timestamp显示到毫秒
1. 插入随机时间的100条数据,测试两个类的使用
package xidian.lili.JDBC;
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Random;
/**
* 测试java.sql.Date和java.sql.TimeStamp
*/
public class Demo07 {
public static void main(String[] args) throws InterruptedException {
PreparedStatement stmt=null;
PreparedStatement stmt2=null;
Connection con=null;
try {
Class.forName("com.mysql.jdbc.Driver");
con=DriverManager.getConnection("jdbc:mysql://localhost:3306/tsetjdbc",
"root", "123456");
String sql="insert into t_user (username,regtime,lastregtime,pwd) values (?,?,?,?);";
stmt=con.prepareStatement(sql);
//设置随机时间,插入1000条数据
//定义一个随机数
for(int i=0;i<100;i++){
int rand=1000000+new Random().nextInt(1000000000);
stmt.setString(1, "王东利"+i);
stmt.setDate(2, new java.sql.Date(System.currentTimeMillis()-rand));
stmt.setTimestamp(3, new java.sql.Timestamp(System.currentTimeMillis()-rand));
stmt.setString(4, "666666");
stmt.executeUpdate();
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
try {
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally{
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(con!=null){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
2. 在插入随机时间的100条数据的查询指定时间范围的对象,查询就有RestultSet
package xidian.lili.JDBC;
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Random;
/**
* 测试java.sql.Date和java.sql.TimeStamp 查询指定范围的数据对象
*/
public class Demo08 {
//给定格式yyyy-MM-dd hh:mm:ss表示时间的字符串转化成long类型的时间值
public static long String2Date(String time){
DateFormat s=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
try {
return s.parse(time).getTime();
} catch (ParseException e) {
e.printStackTrace();
return 0;
}
}
public static void main(String[] args) throws InterruptedException {
PreparedStatement stmt=null;
PreparedStatement stmt2=null;
Connection con=null;
try {
Class.forName("com.mysql.jdbc.Driver");
con=DriverManager.getConnection("jdbc:mysql://localhost:3306/tsetjdbc",
"root", "123456");
String sql="select * from t_user where lastregtime>? and lastregtime<?";
stmt=con.prepareStatement(sql);
Timestamp start=new Timestamp(Demo08.String2Date("2018-06-30 3:23:44"));
Timestamp end=new Timestamp(Demo08.String2Date("2018-07-3 3:23:44"));
stmt.setObject(1, start);
stmt.setObject(2, end);
ResultSet rs=stmt.executeQuery();
while(rs.next()){
System.out.println(rs.getInt("id")+"--"+rs.getString("username")+"--"+rs.getTimestamp("lastregtime"));
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
try {
con.rollback();//遇到异常就回滚
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally{
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(con!=null){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}