-
- 开头,你想使用jdbc连接数据库,先把你默认的数据库字符集改了,改成utf-8看我博客
JDBC概述
-
JDBC(java DataBase Connectivity,数据库连接)是一种用于执行SQL语句的JavaAPI,JDBC是java访问的数据库标准规范,可以为不同的关系型数据库提供统一访问,它由一组用java语言编写的接口和类组成
-
JDBC需要连接驱动,驱动是两个设备要进行通信,满足一定的通信数据格式,数据格式由设备提供商规定,设备提供商为设备提供驱动软件,通过软件可以与该设备进行通信
-
核心:3个接口和一个类:
- DriverManager:驱动管理类,帮组我们加载驱动
- Connection:数据库链接接口,实现类在驱动中
- Statement:执行SQL语句的接口,实现类在驱动中
- ResultSet:结果集接口
-
JDBC是接口,驱动是接口的实现,没有驱动无法完成数据库连接,从而不能操作数据库,每一个数据库厂商都需要提供自己的驱动,用来连接数据,驱动一般是由数据库生成厂商提供
-
步骤:
- 注册驱动:使用DriverManger来注册
- 获取和数据库的连接对象:是connection接口的实现类对象://固定语法: jdbc:数据库厂商://localhost:3306/数据库名
- 这里记住一个问题,你需要添加?useSSL=false,一般mysql通过jdbc方式进行连接都需要这句话,否则会报ssl错误看我博客
- 获取SQL语句的执行者对象,是Statement的实现类对象
- 结果集对象,是ResultSet接口的实现类对象,excute有很多方式,增删该查等
- 处理结果集,使用迭代器
package java学习.jdbc_mysql; import com.mysql.jdbc.Driver; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class JDBCDemo { public static void main(String[] args) throws Exception{ //1.register driver ,use DriverManger to register com.mysql.jdbc.Driver drive = new com.mysql.jdbc.Driver(); DriverManager.registerDriver(drive); //2.get the connection object with the database:the implementation class object of the connection interface String url = "jdbc:mysql://localhost:3306/firstdb?useSSL=false";//固定语法: jdbc:数据库厂商://localhost:3306/数据库名 Connection conn = DriverManager.getConnection(url,"root","666"); //3.get the executor object of the SQL statement,which is the implementation class object of the Statement Statement st = conn.createStatement(); //4.get the result object of the SQL statement,which is the implementation class object of the ResultSet ResultSet rs = st.executeQuery("select * from employee");//excute有很多方式,增删该查等 //5. process the result set,using an iterator while (rs.next()){ Object a1 = rs.getObject("id"); Object a2 = rs.getObject("name"); System.out.println(a1+"\t"+ a2); } //6. close resource,只有执行查询,才有结果集对象,增删改没有结果集对象 rs.close(); st.close(); conn.close(); } }
-
案例:通过工具类,进行简化:
package java学习.jdbc_mysql; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class JDBCUtils { //自己设计一个工具类获取数据库连接 private static String driverName = "com.mysql.jdbc.Driver"; private static String url = "jdbc:mysql://localhost:3306/firstdb?useSSL=false"; private static String username = "root"; private static String password = "666"; //静态代码块,以后不再加载 static { try{ //1.load driver Class.forName(driverName); }catch (Exception e){ System.out.println("驱动加载失败`"); throw new RuntimeException(); } } public static Connection getConnection() throws Exception{ //2.get connection with mysql Connection conn = DriverManager.getConnection(url,username,password); //return object return conn; } //关闭资源 public static void closeAll(Connection conn, Statement st, ResultSet rs){ if (conn == null) { try{ conn.close(); } catch (Exception e){ e.printStackTrace(); } } if (st == null) { try{ st.close(); } catch (Exception e){ e.printStackTrace(); } } if (rs == null) { try{ rs.close(); } catch (Exception e){ e.printStackTrace(); } } } } package java学习.jdbc_mysql; import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement; public class TestDemo1 { public static void main(String[] args) { insert(); delete(); update(); query(); } //插入 public static void insert(){ //1. Connection conn = null; Statement st = null; ResultSet rs = null; try{ conn = JDBCUtils.getConnection(); st = conn.createStatement(); int rows = st.executeUpdate("insert into employee(id,name) values (1005,'咸鱼')"); System.out.println("成功插入"+ rows+"行"); }catch (Exception e){ e.printStackTrace(); }finally { JDBCUtils.closeAll(conn,st,null); } } //删除 public static void delete(){ //1. Connection conn = null; Statement st = null; ResultSet rs = null; try{ conn = JDBCUtils.getConnection(); st = conn.createStatement(); int rows = st.executeUpdate("delete from employee where id = 1003"); System.out.println("成功删除"+ rows+"行"); }catch (Exception e){ e.printStackTrace(); }finally { JDBCUtils.closeAll(conn,st,null); } } //修改 public static void update(){ //1. Connection conn = null; Statement st = null; ResultSet rs = null; try{ conn = JDBCUtils.getConnection(); st = conn.createStatement(); int rows = st.executeUpdate("update employee set name='艾春辉' where id = 1001"); System.out.println("成功修改"+ rows+"行"); }catch (Exception e){ e.printStackTrace(); }finally { JDBCUtils.closeAll(conn,st,null); } } //查询 public static void query(){ //1. Connection conn = null; Statement st = null; ResultSet rs = null; try{ conn = JDBCUtils.getConnection(); st = conn.createStatement(); rs = st.executeQuery("select * from employee"); while (rs.next()){ Object cid = rs.getObject("id"); Object cname = rs.getObject("name"); System.out.println(cid+" "+cname); } }catch (Exception e){ e.printStackTrace(); }finally { JDBCUtils.closeAll(conn,st,null); } } }
-
JDBC:java语言操作各种数据库的技术
- 由一堆接口和类组成
- 类:DriverManger:用于注册驱动
- Connection:数据库链接类的跟接口
- Statement:数据库语句执行类的根接口
- ResultSet:结果集类的跟接口
- 以上接口的实现类,在驱动包中
-
步骤:
-
注册驱动:DriverManger.register(new com.mysql.jdbc.Driver()) 或者Class.forName(“com.mysql.jdbc.Driver”)
-
获取链接:驱动连接串 用户名 密码
Connection conn = DriverManager.getConnection(“jdbc:mysql://ip地址:3306/数据库名”,用户名,密码)
-
获取sql语句执行对象
Statement st = conn.createStatement();或者PreparedStatement pst = conn.prepareStarement(String sql) pst.setObject(序号,参数)
-
使用执行对象执行sql语句,获取到结果集
-
处理结果集: rs.next()//判断有没有下一条记录 rs.getObject(属性名)
-
预处理对象
-
SQL注入问题:用户输入的内容作为了SQL语句语法的一部分,改变了SQL真正的意义
-
假设有登录案例如下:select * from 用户表 where name = username and password = password
-
此时,当用户输入正确的账号和密码后,查询到了信息则让用户登录,但是当用户输入账号为XXX 密码为XXX’ OR ‘a’ = 'a真正的执行代码为
select * from 用户表 where name = ‘xxx’ and password =’ xxx’ or ‘a’=’ a’;
-
此时,上述查询语句`永远都是可以查询出结果的,那么用户和就直接登入成功了,显然我们不希望看到这样的结果这就是sql注入问题
-
-
解决方法:使用preparedStatement:预编译对象是Statement 对象的子类,让这个sql语句中
- 性能高
- 会把SQL语句先编译
- 能过滤掉用户输入的关键字
- PreparedStatement预处理对象,处理的每一条sql语句中所有的时间参数,都必须用?替换
- 使用方法:conn.PrepareStatement(sql语句)//注意sql语句中需要传入的参数都是问号代替,st.setObject(index,x)通过问好的角标进行参数传递,从1开始
package java学习.jdbc_mysql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
//防注入方法
public class TestDemo2 {
public static void main(String[] args) {
insert();
delete();
update();
query();
}
//insert
public static void insert(){
Connection conn = null;
PreparedStatement pst = null;
try{
conn = JDBCUtils.getConnection();
String sql = "insert into employee(id,name) values (?,?)";
pst = conn.prepareStatement(sql);
pst.setObject(1,1006);
pst.setObject(2,"咸鱼");
pst.executeUpdate();
System.out.println("成功修改");
}catch (Exception e){
e.printStackTrace();
}finally {
JDBCUtils.closeAll(conn,pst,null);
}
}
//delete
public static void delete(){
Connection conn = null;
PreparedStatement pst = null;
try{
conn = JDBCUtils.getConnection();
String sql = "delete from empolyee where id=?";
pst = conn.prepareStatement(sql);
pst.setObject(1,1006);
pst.executeUpdate();
System.out.println("成功修改");
}catch (Exception e){
e.printStackTrace();
}finally {
JDBCUtils.closeAll(conn,pst,null);
}
}
//update
public static void update(){
Connection conn = null;
PreparedStatement pst = null;
try{
conn = JDBCUtils.getConnection();
String sql = "update employee set name=? where id = ?";
pst = conn.prepareStatement(sql);
pst.setObject(1,"艾春辉");
pst.setObject(2,"1006");
pst.executeUpdate();
System.out.println("成功修改");
}catch (Exception e){
e.printStackTrace();
}finally {
JDBCUtils.closeAll(conn,pst,null);
}
}
//query
public static void query(){
Connection conn = null;
PreparedStatement pst = null;
ResultSet rs = null;
try{
conn = JDBCUtils.getConnection();
String sql = "select * from employee where name like ?";
pst = conn.prepareStatement(sql);
pst.setObject(1,"%春%");
rs = pst.executeQuery();
while(rs.next()){
Object uid = rs.getObject("id");
System.out.println(uid);
}
System.out.println("成功修改");
}catch (Exception e){
e.printStackTrace();
}finally {
JDBCUtils.closeAll(conn,pst,null);
}
}
}
DBCPutils
-
解决数据库连接耗费资源和时间很多的问题,提高性能
-
connection对象在JDBC使用的时候,使用的时候就会去创建一个对象,使用结束以后就会将这个对象给销毁了,每次创建和销毁对象都是耗时操作,需要使用连接词对其进行优化,程序初始化的时候,初始化多个连接,将多个连接放入到池中,每次获取的时候,都可以直接从连接池中进行获取,使用结束以后,将连接归还到池中
-
javax.sql.DataSource数据源:初始化多个连接,将多个连接放入到内存中,将连接对象放回到内存中
-
常见连接池:DBCP
-
在dbcp连接池中,实现javax.sql.DataSource
-
带有配置文件的DBCP的使用,核心类:BasicDataSourceFactory(工厂) public static DataSource createDataSource(new FileInputStream…){}
package java学习.jdbc_mysql; import org.apache.commons.dbcp.BasicDataSource; import org.apache.commons.dbcp.BasicDataSourceFactory; import javax.sql.DataSource; import java.io.FileInputStream; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; public class DBCPUtils { // public static String driverName = "com.mysql.jdbc.Driver"; // public static String url = "jdbc:mysql://localhost:3306/firstdb?useSSL=false"; // public static String username = "root"; // public static String password = "666"; // public static BasicDataSource ds = new BasicDataSource(); private static DataSource ds = null; // Static code block sets the 4 major elements of ds static { try { Properties ps = new Properties(); ps.load(DBCPUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties")); ds = BasicDataSourceFactory.createDataSource(ps); // ds.setDriverClassName(driverName); // ds.setUrl(url); // ds.setUsername(username); // ds.setPassword(password); } catch (Exception e) { } } public static Connection getConnection() throws SQLException { //return connection object ,not from Drivermanager but from DBCPUtils return ds.getConnection(); } //关闭资源 public static void closeAll(Connection conn, Statement st, ResultSet rs) { if (conn == null) { try { conn.close(); } catch (Exception e) { e.printStackTrace(); } } if (st == null) { try { st.close(); } catch (Exception e) { e.printStackTrace(); } } if (rs == null) { try { rs.close(); } catch (Exception e) { e.printStackTrace(); } } } }
-
DBUtils框架介绍
-
DBUtils:主要负责关闭连接,释放资源,开启事物等操作
-
QueryRunner:负责我们对象的数据库增删改查操作(核心类)
-
ResultSetHandler:结果集处理类,帮助我们处理结果集,帮助我们封装数据的
-
QueryRunner:类的使用
-
构造:public QueryRunner(DataSource ds)需要一个连接池
-
方法:update(String sql, Object …params)//主要执行增删改 query(String sql, ResultSetHandler,Object …params)//主要执行查询操作
-
ResultSetHandler是一个接口:实现类
-
ArrayHandler:将结果集中的第一条记录封装到一个Object数组中,数组中每一个元素就是这条记录,就是将数据库中的目标内容拿出来,但是只会处理第一条
-
ArrayListHandler:同上,但是会把所有的相关内容打出来,而不是只打印一条
//create QueryRunner Object QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource()); //query String sql = "select * from employee"; List<Object[]> list = qr.query(sql,new ArrayListHandler()); for (Object[] Objects:list) { System.out.println(Objects[0]+" "+Objects[1]); } }
-
BeanHandler处理类:会把对象按照一个类的格式存储,只处理一个
//create QueryRunner Object QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource()); //query String sql = "select * from employee"; Category c = qr.query(sql,new BeanHandler<Category>(Category.class)); System.out.println(c); package com.itheima.domain; /** * 标准的javabean * @author yingpeng * */ public class Category { private String cid; private String cname; public String getCid() { return cid; } public void setCid(String cid) { this.cid = cid; } public String getCname() { return cname; } public void setCname(String cname) { this.cname = cname; } @Override public String toString() { return "Category [cid=" + cid + ", cname=" + cname + "]"; } public Category() { super(); // TODO Auto-generated constructor stub } public Category(String cid, String cname) { super(); this.cid = cid; this.cname = cname; } }
-
BeanListHandler处理类:会把对象按照一个类的格式存储,存储全部事件
-
ClumnListHandler,将结果指定的列字段值,封装在list中
//create QueryRunner Object QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource()); //query String sql = "select * from employee"; List<Integer> c = qr.query(sql,new ColumnListHandler<Integer>("id")); System.out.println(c);
-
MapHandler:键值对,储存两列,但是只返回第一组数据,key就是字段名称,value就是字段值
-
MapListHandler:键值对,能返回全部组数据
-
ScalarHandler:它是用于单个数据,一般是聚合函数的操作: select count(*) from 表操作
//create QueryRunner Object QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource()); //query String sql = "select * from employee"; Integer count = qr.query(sql,new ScalarHandler<Integer>()); System.out.println(count);
-
-
C3P0
-
C3P0是一个开源的JDBC连接池,它实现了数据源和JND绑定,支持JDBC3规范和JDBC2的扩展,对于后面要学的框架有很大帮助
-
在连接池中,遵循了javax.sql.DataSource接口的实现类:ComboPooledDataSource
package java学习.jdbc_mysql; import com.mchange.v2.c3p0.ComboPooledDataSource; import java.sql.Connection; import java.sql.SQLException; public class C3P0Utils { // public static String driverName = "com.mysql.jdbc.Driver"; // public static String url = "jdbc:mysql://localhost:3306/firstdb?useSSL=false"; // public static String username = "root"; // public static String password = "666"; public static ComboPooledDataSource ds = new ComboPooledDataSource(); // Static code block sets the 4 major elements of ds static { try { // ds.setDriverClass(driverName); // ds.setJdbcUrl(url); // ds.setUser(username); // ds.setPassword(password); }catch (Exception e){ } } public static Connection getConnection() throws SQLException { //return connection object ,not from Drivermanager but from DBCPUtils return ds.getConnection(); } }
-
c3p0配置:
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <default-config> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/firstdb?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=UTC</property> <property name="user">root</property> <property name="password">666</property> <property name="initialPoolSize">10</property> </default-config> </c3p0-config>
案例
-
需求:设计一个界面,输入三个值,一个收款人,一个收款人,一个转账的金额,不嗯给你出现付款人的钱被扣除而收款人的钱为到账
-
事务的概述:什么是事务:事务指的是逻辑上的一组操作,组成这组操作的各个单元要么全都成功,要么全都失败.事务作用:保证在一个事务中多次操作要么全都成功,要么全都失败.实例:
update account set money=money-100 where name='tom'//tom转出100块 update account set money=money+100 where name='jerry'//jerry收到100块 以上两个sql语句,我们需要把他们看成一个事务
-
sql语句
- 开启事务:start transaction ,java中使用setAutoCommit自动提交方法
- 提交事务:commit,使上一次提交/回滚后进行的更改称为持久更改,并释放connection对象当前所持有的所有数据库锁
- 回滚事务:rollback,取消在当前事务的所有更改,并释放次connection对象当前持有的所有数据库锁
package java学习.jdbc案例; import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; //模拟jack给tom转帐1000元 //update account set money=money-1000 where name = 'jack' //update account set money=money+1000 where name = 'tom' public class AccountDemo { public static void main(String[] args) throws Exception{ Statement st = null; Connection conn = null; try { //注册驱动 Class.forName("com.mysql.jdbc.Driver"); //获取连接 conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day06?useSSL=false","root","***"); //在所有操作之前开启事务 conn.setAutoCommit(false);//设置自动提交事务,就是开启事务 //获取sql执行对象 st = conn.createStatement(); //1.jack减少1000 int row1 = st.executeUpdate("update account set money=money-1000 where name = 'jack'"); System.out.println(1 / 0); //2 tom收入1000元 int row2 = st.executeUpdate("update account set money=money+1000 where name = 'tom'"); //所有操作之后 提交事务 conn.commit(); if (row1 > 0 && row2 > 0) System.out.println("转账成功"); }catch (Exception e) { System.out.println("出现事故,进行回滚"); conn.rollback(); //auto-generated catch block e.printStackTrace(); } //释放资源 st.close(); // conn.close(); } }
DBUtils框架案例:
-
为了支持事务,不能传递连接池//QueryRunner qr = new QueryRunner
package java学习.jdbc案例; import com.mchange.v2.c3p0.ComboPooledDataSource; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; public class C3P0Utils { public static String driverName = "com.mysql.jdbc.Driver"; public static String url = "jdbc:mysql://localhost:3306/day06?useSSL=false"; public static String username = "root"; public static String password = "***"; public static ComboPooledDataSource ds = new ComboPooledDataSource(); // Static code block sets the 4 major elements of ds static { try { ds.setDriverClass(driverName); ds.setJdbcUrl(url); ds.setUser(username); ds.setPassword(password); }catch (Exception e){ } } public static Connection getConnection() throws SQLException { //return connection object ,not from Drivermanager but from DBCPUtils return ds.getConnection(); } public static DataSource getDataSource(){ return ds; } } package java学习.jdbc案例; import org.apache.commons.dbutils.QueryRunner; import java.sql.Connection; import java.sql.SQLException; public class AccountDemo2 { public static void main(String[] args) throws SQLException { //创建一个QueryRunner对象 QueryRunner qr = new QueryRunner();//为了使用事务,不能使用带参数的构造函数 Connection conn = null; try { conn = C3P0Utils.getConnection(); System.out.println(qr); //开启事务 conn.setAutoCommit(false); //执行转账功能 //减钱 int row1 = qr.update(conn, "update account set money=money-? where name = ?", 1000, "jack"); //加钱 int row2 = qr.update(conn, "update account set money=money+? where name = ?", 1000, "tom"); //提交事务 conn.commit(); if (row1 > 0 && row2 < 0) System.out.println("转账成功"); }catch (Exception e) { conn.rollback(); System.out.println("转账出现问题,程序失败"); e.printStackTrace(); } } }
使用mvc框架进行设计转账案例
- mvc是模型-视图-控制器,是一种软件设计典范,用一种业务逻辑数据,界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性定制界面及用户交互界面的同时,不需要重新编写业务逻辑
-
数据库操作底层
package java学习.jdbc案例.dao; import java学习.jdbc案例.utils.C3P0Utils; import java学习.jdbc案例.utils.ConnectionManager; import org.apache.commons.dbutils.QueryRunner; import java.sql.Connection; import java.sql.SQLException; //转账的dao层,主要操作数据库 public class AccountDAO { //转账出去 public void fromAccount(String fromName, double money)throws SQLException{ Connection conn = ConnectionManager.getConnection(); //创建query对象 QueryRunner qr = new QueryRunner(); //执行减钱操作 qr.update(conn,"update account set money=money-? where name=?",money,fromName); } //收钱 public void toAccount(String toName,double money)throws SQLException{ Connection conn = ConnectionManager.getConnection(); //创建一个QueryRunner对象 QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource()); //加钱操作 qr.update(conn,"update account set money=money+? where name=?",money,toName); } }
-
转账功能的业务层
package java学习.jdbc案例.service; import java学习.jdbc案例.C3P0Utils; import java学习.jdbc案例.dao.AccountDAO; import java学习.jdbc案例.utils.ConnectionManager; import java.sql.Connection; public class AccountService { //转账业务 public void transfer(String fromName,String toName,double money){ //直接调用业务层 AccountDAO dao = new AccountDAO(); Connection conn = null; try { conn = ConnectionManager.getConnection(); //开启事务 ConnectionManager.start(); //转出去 dao.fromAccount(fromName, money); //拿回来 dao.toAccount(toName, money); //提交事务 conn.commit(); System.out.println("成功"); }catch (Exception e){ e.printStackTrace(); System.out.println("程序失败,事务回滚"); try { conn.rollback(); }catch (Exception e1) { e1.printStackTrace(); } }finally { try { conn.close(); }catch (Exception e2) { e2.printStackTrace(); } } } }
-
工具类层:
两个工具类: package java学习.jdbc案例.utils; import com.mchange.v2.c3p0.ComboPooledDataSource; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; public class C3P0Utils { public static String driverName = "com.mysql.jdbc.Driver"; public static String url = "jdbc:mysql://localhost:3306/day06?useSSL=false"; public static String username = "root"; public static String password = "666"; public static ComboPooledDataSource ds = new ComboPooledDataSource(); // Static code block sets the 4 major elements of ds static { try { ds.setDriverClass(driverName); ds.setJdbcUrl(url); ds.setUser(username); ds.setPassword(password); }catch (Exception e){ } } public static Connection getConnection() throws SQLException { //return connection object ,not from Drivermanager but from DBCPUtils return ds.getConnection(); } public static DataSource getDataSource(){ return ds; } } package java学习.jdbc案例.utils; import java.sql.Connection; import java.sql.SQLException; //连接管理类,主要负责获取连接,开启事务,提交事务,回滚事务 public class ConnectionManager { //定义一个集合ThreadLocal对象来保存当前线程连接 private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>(); //获取连接 public static Connection getConnection() throws SQLException { //从tl中获取连接 Connection conn = tl.get(); if(conn == null){ conn = C3P0Utils.getConnection(); tl.set(conn); } return conn; } //开启事务 public static void start() throws SQLException{ ConnectionManager.getConnection().setAutoCommit(false); } //提交事务 public static void commit() throws SQLException{ ConnectionManager.getConnection().commit(); } //回滚事务 public static void rollback() throws SQLException{ ConnectionManager.getConnection().rollback(); } //关闭连接 public static void close() throws SQLException{ ConnectionManager.getConnection().close(); } }
-
事务特性解释:
-
原子性:强调事务的不可分割.
-
一致性:事务的执行的前后,数据的完整性保持一致.
-
隔离性:一个事务在执行的过程中,不应该受到其他事务的干扰.
-
持久性:事务一旦结束,数据就持久到数据库中
-
-
如果不考虑事务的隔离性,引发一些安全问题
-
脏读 :一个事务读到了另一个事务未提交的数据.
-
不可重复读 :一个事务读到了另一个事务已经提交(update)的数据.引发一个事务中的多次查询结果不一致.
-
虚读/幻读 :一个事务读到了另一个事务已经提交的(insert)数据.导致多次查询的结果不一致
-
-
设置事务的隔离级别:
-
read uncommitted :脏读,不可重复读,虚读都可能发生.
-
read committed :避免脏读,但是不可重复读和虚读有可能发生.(Oracle默认)
-
repeatable read :避免脏读和不可重复读,但是虚读有可能发生的(MySql默认)
-
serializable :避免脏读,不可重复读和虚读.(串行化的-不可能出现事务并发访问)
-
使用JDBC进行隔离级别的设置
- void setTransactionIsolation(int level):视图将此Connection对象的事务隔离级别更改为给定的级别
- static int TRANSACTION_NONE:指示事务不受支持的常量
- static int TRANSACTION_READ_COMMITTED 指示不可以发生脏读的常量;不可重复读和虚读可以发生
- static int TRANSACTION_READ_UNCOMMITTED:指示可以发生脏读,不可重复读和虚读的常量
- static int TRANSACTION_REPEATABLE_READ:指示不可以发生脏读和不可重复读的常量,虚读可以发生
- static int TRANSACTION_SERTALIZABLE:指示不可以发生脏读 不可重复度和虚读的常量
案例2:商品信息储存
-
首先使用mvc思想进行设计,我设计的内容框架是这样的
-
productDao:实际操作数据库
package java学习.jdbc案例.demo2.service; //商品service层 import java学习.jdbc案例.demo2.dao.ProductDao; import java学习.jdbc案例.demo2.domain.Product; import java学习.jdbc案例.demo2.utils.C3P0Utils; import java学习.jdbc案例.demo2.utils.ConnectionManager; import org.apache.commons.dbutils.QueryRunner; import java.sql.Connection; import java.sql.SQLException; import java.util.List; public class ProductService { //添加商品 public void addProduct(Product p){ ProductDao dao = new ProductDao(); try{ dao.addProduct(p); }catch (Exception e) { e.printStackTrace(); } } public Product findById(int id)throws SQLException { ProductDao dao = new ProductDao(); Product p = null; try { p = dao.findById(id); }catch (Exception e){ e.printStackTrace(); } return p; } //修改商品 public void updateProduct(Product p){ ProductDao dao = new ProductDao(); try{ dao.updateProduct(p); }catch (Exception e){ e.printStackTrace(); } } //查询所有商品 public List<Product> findAll() throws SQLException{ ProductDao dao = new ProductDao(); List<Product> ps = null; try{ ps = dao.findAll(); }catch (SQLException e){ e.printStackTrace(); } return ps; } //根据id删除商品 public void deleteById(int id)throws SQLException{ ProductDao dao = new ProductDao(); try{ dao.deleteByOneId(id); }catch (SQLException e){ e.printStackTrace(); } } //批量删除商品 public void deleteAll(List<Integer> ids)throws SQLException{ //循环调用deleteById方法 ProductDao dao = new ProductDao(); try{ ConnectionManager.start(); for (int id:ids) { dao.deleteById(id); System.out.println(1/0); } ConnectionManager.commit(); }catch(Exception e){ e.printStackTrace(); ConnectionManager.rollback(); } } }
-
Product:结构层,主要对应的是数据库里面的一个表的字段
package java学习.jdbc案例.demo2.domain; public class Product { private int pid; private String pname; private int price; private String flag; private String category_id; public int getPid() { return pid; } public void setPid(int pid) { this.pid = pid; } public String getPname() { return pname; } public void setPname(String pname) { this.pname = pname; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } public String getFlag() { return flag; } public void setFlag(String flag) { this.flag = flag; } public String getCategory_id() { return category_id; } public void setCategory_id(String category_id) { this.category_id = category_id; } @Override public String toString() { return "Product [pid=" + pid + ", pname=" + pname + ", price=" + price + ", flag=" + flag + ", category_id=" + category_id + "]"; } public Product() { super(); // TODO Auto-generated constructor stub } public Product(int pid, String pname, int price, String flag, String category_id) { super(); this.pid = pid; this.pname = pname; this.price = price; this.flag = flag; this.category_id = category_id; } public Product(String pname, int price) { super(); this.pname = pname; this.price = price; } }
-
ProductService :服务层,上接视图层,下接数据库操作层
package java学习.jdbc案例.demo2.service; //商品service层 import java学习.jdbc案例.demo2.dao.ProductDao; import java学习.jdbc案例.demo2.domain.Product; import java学习.jdbc案例.demo2.utils.C3P0Utils; import java学习.jdbc案例.demo2.utils.ConnectionManager; import org.apache.commons.dbutils.QueryRunner; import java.sql.Connection; import java.sql.SQLException; import java.util.List; public class ProductService { //添加商品 public void addProduct(Product p){ ProductDao dao = new ProductDao(); try{ dao.addProduct(p); }catch (Exception e) { e.printStackTrace(); } } public Product findById(int id)throws SQLException { ProductDao dao = new ProductDao(); Product p = null; try { p = dao.findById(id); }catch (Exception e){ e.printStackTrace(); } return p; } //修改商品 public void updateProduct(Product p){ ProductDao dao = new ProductDao(); try{ dao.updateProduct(p); }catch (Exception e){ e.printStackTrace(); } } //查询所有商品 public List<Product> findAll() throws SQLException{ ProductDao dao = new ProductDao(); List<Product> ps = null; try{ ps = dao.findAll(); }catch (SQLException e){ e.printStackTrace(); } return ps; } //根据id删除商品 public void deleteById(int id)throws SQLException{ ProductDao dao = new ProductDao(); try{ dao.deleteByOneId(id); }catch (SQLException e){ e.printStackTrace(); } } //批量删除商品 public void deleteAll(List<Integer> ids)throws SQLException{ //循环调用deleteById方法 ProductDao dao = new ProductDao(); try{ ConnectionManager.start(); for (int id:ids) { dao.deleteById(id); System.out.println(1/0); } ConnectionManager.commit(); }catch(Exception e){ e.printStackTrace(); ConnectionManager.rollback(); } } }
-
C3P0Utils和ConnectionManager:工具类集合,两个工具类,一个是配置数据库连接,一个是管理数据库连接
package java学习.jdbc案例.demo2.utils; import com.mchange.v2.c3p0.ComboPooledDataSource; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; public class C3P0Utils { public static String driverName = "com.mysql.jdbc.Driver"; public static String url = "jdbc:mysql://localhost:3306/day07?useSSL=false"; public static String username = "root"; public static String password = "***"; public static ComboPooledDataSource ds = new ComboPooledDataSource(); // Static code block sets the 4 major elements of ds static { try { ds.setDriverClass(driverName); ds.setJdbcUrl(url); ds.setUser(username); ds.setPassword(password); }catch (Exception e){ } } public static Connection getConnection() throws SQLException { //return connection object ,not from Drivermanager but from DBCPUtils return ds.getConnection(); } public static DataSource getDataSource(){ return ds; } } package java学习.jdbc案例.demo2.utils; import java学习.jdbc案例.demo2.utils.C3P0Utils; import java.sql.Connection; import java.sql.SQLException; //连接管理类,主要负责获取连接,开启事务,提交事务,回滚事务 public class ConnectionManager { //定义一个集合ThreadLocal对象来保存当前线程连接 private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>(); //获取连接 public static Connection getConnection() throws SQLException { //从tl中获取连接 Connection conn = tl.get(); if(conn == null){ conn = C3P0Utils.getConnection(); tl.set(conn); } return conn; } //开启事务 public static void start() throws SQLException{ ConnectionManager.getConnection().setAutoCommit(false); } //提交事务 public static void commit() throws SQLException{ ConnectionManager.getConnection().commit(); } //回滚事务 public static void rollback() throws SQLException{ ConnectionManager.getConnection().rollback(); } //关闭连接 public static void close() throws SQLException{ ConnectionManager.getConnection().close(); } }
-
ProductView:视图层
package java学习.jdbc案例.demo2.view; import java学习.jdbc案例.demo2.domain.Product; import java学习.jdbc案例.demo2.service.ProductService; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class ProductView { public static void main(String[] args) throws SQLException{ //显示菜单 System.out.println("欢迎来到商品管理系统,请输入命令进行操作:"); while (true) { System.out.println("C:新增 U:修改 D:删除 DA:批量删除 FI:查询 FA:查询所有 Q:退出"); //获取用户输入 Scanner sc = new Scanner(System.in); String userSelect = sc.nextLine(); //判断用户输入的到底是哪一个命令 switch (userSelect.toUpperCase()) { case "C": //新增商品 addProduct(); break; case "U": //修改商品 editProduct(); break; case "D": //删除商品 deleteProduct(); break; case "DA": //删除全部商品 deleteAllProduct(); break; case "FI": //根据id查询 findById(); break; case "FA": //查询所有商品 findAll(); break; case "Q": //退出 System.out.println("退出"); System.exit(0);//结束正在执行的jvm虚拟机 break; default: System.out.println("请重新输入"); break; } } } //添加商品功能 private static void addProduct(){ Scanner sc = new Scanner(System.in); System.out.println("您选择了新增商品功能"); //请输入新的商品名字 System.out.println("请输入新增商品名字:"); String name = sc.nextLine(); //请输入新的商品价格 System.out.println("请输入新的商品价格:"); int price = Integer.parseInt(sc.nextLine()); //封装成商品对象 Product p = new Product(name,price); //调用service层的添加商品方法 ProductService service = new ProductService(); service.addProduct(p); System.out.println("新增商品成功"); } private static void editProduct()throws SQLException{ Scanner sc = new Scanner(System.in); System.out.println("您选择了修改商品功能"); //请输入需要修改的商品编号 System.out.println("请输入需要修改的商品编号:"); int id = Integer.parseInt(sc.nextLine()); //查询数据库,如果有就告诉用户选择商品是什么信息 ProductService service = new ProductService(); Product p = service.findById(id); if(p==null) System.out.println("您要修改的商品不存在,商品编号是"+id); else{ //商品存在 System.out.println("您要修改的商品信息如下:"); System.out.println(p); //请输入商品新的名字 System.out.println("请输入商品新的名字:"); String newName = sc.nextLine(); //请输入新的商品价格 System.out.println("请输入商品新的价格:"); int newprice = Integer.parseInt(sc.nextLine()); //设置新的名字和价格 p.setPname(newName); p.setPrice(newprice); //调用service层 service.updateProduct(p); System.out.println("修改商品成功"); } } private static void deleteProduct()throws SQLException{ Scanner sc = new Scanner(System.in); System.out.println("您选择了删除商品功能"); System.out.println("请输入要删除的商品编号:"); int id = Integer.parseInt(sc.nextLine()); //如果有则告诉此id商品的具体信息 ProductService service = new ProductService(); Product p = service.findById(id); if(p == null) { System.out.println("查无此商品"); }else { System.out.println("您要删除的商品如下"); System.out.println(p); System.out.println("是否删除此商品?:Y/N"); String isOrNot = sc.nextLine(); if("Y".equals(isOrNot.toUpperCase())) { service.deleteById(id); System.out.println("删除商品成功"); }else { System.out.println("操作取消"); } } } private static void deleteAllProduct()throws SQLException{ Scanner sc = new Scanner(System.in); ProductService service = new ProductService(); System.out.println("您选择了批量删除商品功能"); //创建一个集合 List<Integer> ids = new ArrayList<>(); while (true) { System.out.println("请输入您要删除的商品编号,(-1表示结束)"); int deleteId = Integer.parseInt(sc.nextLine()); if(deleteId == -1){ break; } Product p = service.findById(deleteId); if (p != null) { ids.add(deleteId); System.out.println("已经标记此商品..."); } else { System.out.println("此商品不存在,请重新输入"); } } if (ids.isEmpty()){ System.out.println("批量删除操作已经取消"); }else{ System.out.println("您一共标记了"+ids.size()+"个商品"); System.out.println("您确定都要删除吗? y/n"); String isOrNot = sc.nextLine(); if ("Y".equals(isOrNot.toUpperCase())){ service.deleteAll(ids); System.out.println("删除商品成功"); }else System.out.println("删除取消"); } } private static void findById()throws SQLException{ Scanner sc = new Scanner(System.in); System.out.println("您选择了查询商品功能"); //请输入您要查询的商品编号 System.out.println("请输入您要查询的商品编号:"); int id = Integer.parseInt(sc.nextLine()); //查询数据库,查看是否有此方法,调用service方法 ProductService service = new ProductService(); Product p = service.findById(id); //展示并进行判断 if (p==null) System.out.println("查询商品不存在,请确认后输入"); else { System.out.println("查询商品---"+ p); System.out.println("查询商品成功"); } } private static void findAll()throws SQLException{ System.out.println("您选择了查询全部商品功能"); ProductService service = new ProductService(); List<Product> ps = service.findAll(); if (ps == null) System.out.println("您的仓库里面没有商品"); else { for (Product p : ps) { System.out.println(p); } System.out.println("查询商品成功"); } } }
-
总结
-
SQL语句:
-
DDL:数据库定义语言:数据库定义语言,主要对数据库,表,列进行增删改查
- 创建数据库:create database 数据名(charset 字符集名)
- 创建表: create table 表名:(字段名 数据类型 长度 )
- SQL中的数据类型:整数:int 小数:double 字符串:varchar()长度,建议使用2的整数倍,日期?格式’yyyy-mm-dd’
- 主键约束primary key 唯一且非空,自动增长列约束auto_increment,必须是数值类型,而且一般我们会给主键加上自增长约束,唯一约束unique,多个记录的该列的值不能相同,非空约束not null不能为空,默认约束default,默认约束,为某一个字段设置默认值,外键约束foreign key多表查询
-
DCL:数据库控制语言
-
DML:数据库操作语言:
- insert into 表名 (字段…) values (值1,2,3)
- 注意事项,字段与值要一一对应,如果是全字段,表名后面可以不写,但是values必须写上全部字段的值,值的写法,除了数值类型的值,其他类型的值必须用’'或者""括起来
- 删除: delete from 表明(where 条件) trancate table表明:以上两种删除表的区别,delete:只会删除记录,不会重置自动增长集,trancate:摧毁表,再重建,即会删除所有记录,也会重置自动增长值
-
DQL:数据库查询语言
-
单表查询: select * from 表名 where 条件:> < >= <= = != <>
区间: berween .. and .. 只能判断数值和日期 like '表达式' ,符号_表示任意一个字符,符号%表示任意个任意字符 排序查询:select * from 表名 order by 字段 ASC(默认升序 |DESC(降序;) 聚合查询:select count(*)|max(数值字段)|min(数值字段)|sum(数值字段)|avg(数值字段) from 表名 注意事项:聚合函数查询出来的只有一个值,会忽略null 分组查询: 字段1,字段2,from 表名 group by 某个字段;在分组查询中,要查询的字段必须是分组字段,也可以是聚合函数 分页查询:select * from 表名 limit 第几条记录,要查询第三条记录:比如我要查询第m页,每页有n条记录 第一页:limit (1-1)*n,n; 第二页: limit n,n; 去重复: select distinct 字段...from 表
-
多表查询:
一对多:必须两张表,一张主表,一张从表; 原则:从表必须有一个外键,这个外间引用主表的主键 添加外检约束:alter table 从表 add constraint 主表_从表_fk foreign key (从表外键名) references 主表(主键名); 多对多: 必须有三张表:两张正常表,一张中间表 原则;中间表,至少有两个字段,分别是外键,引用两张表的主键 多表查询语句: 1. 交叉查询:本身错误,实际上是一种笛卡尔积的东西: select * from 表1,表2; 2. 内连接:在交叉连接的基础上,添加条件 隐式内连接:不写inner join 后面的条件用where判断 显示内连接:写上inner join 后面用on 来表示 3. 外连接:关键字 outer join 左外连接:left outer join 右外连接:right outer join
-
-