java_08JDBC

    • 开头,你想使用jdbc连接数据库,先把你默认的数据库字符集改了,改成utf-8看我博客

JDBC概述

  • JDBC(java DataBase Connectivity,数据库连接)是一种用于执行SQL语句的JavaAPI,JDBC是java访问的数据库标准规范,可以为不同的关系型数据库提供统一访问,它由一组用java语言编写的接口和类组成

  • JDBC需要连接驱动,驱动是两个设备要进行通信,满足一定的通信数据格式,数据格式由设备提供商规定,设备提供商为设备提供驱动软件,通过软件可以与该设备进行通信

    java_08JDBC_第1张图片

  • 核心:3个接口和一个类:

    1. DriverManager:驱动管理类,帮组我们加载驱动
    2. Connection:数据库链接接口,实现类在驱动中
    3. Statement:执行SQL语句的接口,实现类在驱动中
    4. ResultSet:结果集接口
  • JDBC是接口,驱动是接口的实现,没有驱动无法完成数据库连接,从而不能操作数据库,每一个数据库厂商都需要提供自己的驱动,用来连接数据,驱动一般是由数据库生成厂商提供

    java_08JDBC_第2张图片

  • 步骤:

    1. 注册驱动:使用DriverManger来注册
    2. 获取和数据库的连接对象:是connection接口的实现类对象://固定语法: jdbc:数据库厂商://localhost:3306/数据库名
    3. 这里记住一个问题,你需要添加?useSSL=false,一般mysql通过jdbc方式进行连接都需要这句话,否则会报ssl错误看我博客
    4. 获取SQL语句的执行者对象,是Statement的实现类对象
    5. 结果集对象,是ResultSet接口的实现类对象,excute有很多方式,增删该查等
    6. 处理结果集,使用迭代器
    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语言操作各种数据库的技术

    1. 由一堆接口和类组成
    2. 类:DriverManger:用于注册驱动
    3. Connection:数据库链接类的跟接口
    4. Statement:数据库语句执行类的根接口
    5. ResultSet:结果集类的跟接口
    6. 以上接口的实现类,在驱动包中
  • 步骤:

    1. 注册驱动:DriverManger.register(new com.mysql.jdbc.Driver()) 或者Class.forName(“com.mysql.jdbc.Driver”)

    2. 获取链接:驱动连接串 用户名 密码

      Connection conn = DriverManager.getConnection(“jdbc:mysql://ip地址:3306/数据库名”,用户名,密码)

    3. 获取sql语句执行对象

      Statement st = conn.createStatement();或者PreparedStatement pst = conn.prepareStarement(String sql) pst.setObject(序号,参数)

    4. 使用执行对象执行sql语句,获取到结果集

    5. 处理结果集: rs.next()//判断有没有下一条记录 rs.getObject(属性名)

预处理对象

  • SQL注入问题:用户输入的内容作为了SQL语句语法的一部分,改变了SQL真正的意义

    1. 假设有登录案例如下:select * from 用户表 where name = username and password = password

    2. 此时,当用户输入正确的账号和密码后,查询到了信息则让用户登录,但是当用户输入账号为XXX 密码为XXX’ OR ‘a’ = 'a真正的执行代码为

      select * from 用户表 where name = ‘xxx’ and password =’ xxx’ or ‘a’=’ a’;

    3. 此时,上述查询语句`永远都是可以查询出结果的,那么用户和就直接登入成功了,显然我们不希望看到这样的结果这就是sql注入问题

  • 解决方法:使用preparedStatement:预编译对象是Statement 对象的子类,让这个sql语句中

    1. 性能高
    2. 会把SQL语句先编译
    3. 能过滤掉用户输入的关键字
    4. PreparedStatement预处理对象,处理的每一条sql语句中所有的时间参数,都必须用?替换
    5. 使用方法: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

    1. 在dbcp连接池中,实现javax.sql.DataSource

    2. 带有配置文件的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:类的使用

    1. 构造:public QueryRunner(DataSource ds)需要一个连接池

    2. 方法:update(String sql, Object …params)//主要执行增删改 query(String sql, ResultSetHandler,Object …params)//主要执行查询操作

    3. ResultSetHandler是一个接口:实现类

      1. ArrayHandler:将结果集中的第一条记录封装到一个Object数组中,数组中每一个元素就是这条记录,就是将数据库中的目标内容拿出来,但是只会处理第一条

      2. ArrayListHandler:同上,但是会把所有的相关内容打出来,而不是只打印一条

         //create QueryRunner Object
                QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
                //query
                String sql = "select * from employee";
                List list = qr.query(sql,new ArrayListHandler());
                for (Object[] Objects:list) {
                    System.out.println(Objects[0]+" "+Objects[1]);
                }
            }
        
      3. BeanHandler处理类:会把对象按照一个类的格式存储,只处理一个

         //create QueryRunner Object
                QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
                //query
                String sql = "select * from employee";
                Category c = qr.query(sql,new BeanHandler(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;
        	}
        	
        }
        
      4. BeanListHandler处理类:会把对象按照一个类的格式存储,存储全部事件

      5. ClumnListHandler,将结果指定的列字段值,封装在list中

         //create QueryRunner Object
                QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
                //query
                String sql = "select * from employee";
                List c = qr.query(sql,new ColumnListHandler("id"));
                System.out.println(c);
        
      6. MapHandler:键值对,储存两列,但是只返回第一组数据,key就是字段名称,value就是字段值

      7. MapListHandler:键值对,能返回全部组数据

      8. 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());
                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配置:

    
    
      
        com.mysql.jdbc.Driver
        jdbc:mysql://localhost:3306/firstdb?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=UTC
        root
        666
        10
    
      
    
     
    
    

案例

  • 需求:设计一个界面,输入三个值,一个收款人,一个收款人,一个转账的金额,不嗯给你出现付款人的钱被扣除而收款人的钱为到账

  • 事务的概述:什么是事务:事务指的是逻辑上的一组操作,组成这组操作的各个单元要么全都成功,要么全都失败.事务作用:保证在一个事务中多次操作要么全都成功,要么全都失败.实例:

    update account set money=money-100 where name='tom'//tom转出100块
    update account set money=money+100 where name='jerry'//jerry收到100块
    以上两个sql语句,我们需要把他们看成一个事务
    
  • sql语句

    1. 开启事务:start transaction ,java中使用setAutoCommit自动提交方法
    2. 提交事务:commit,使上一次提交/回滚后进行的更改称为持久更改,并释放connection对象当前所持有的所有数据库锁
    3. 回滚事务: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是模型-视图-控制器,是一种软件设计典范,用一种业务逻辑数据,界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性定制界面及用户交互界面的同时,不需要重新编写业务逻辑

java_08JDBC_第3张图片

  • 数据库操作底层

    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 tl = new ThreadLocal();
        //获取连接
        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();
        }
    }
    
    
  • 事务特性解释:

    1. 原子性:强调事务的不可分割.

    2. 一致性:事务的执行的前后,数据的完整性保持一致.

    3. 隔离性:一个事务在执行的过程中,不应该受到其他事务的干扰.

    4. 持久性:事务一旦结束,数据就持久到数据库中

  • 如果不考虑事务的隔离性,引发一些安全问题

    1. 脏读 :一个事务读到了另一个事务未提交的数据.

    2. 不可重复读 :一个事务读到了另一个事务已经提交(update)的数据.引发一个事务中的多次查询结果不一致.

    3. 虚读/幻读 :一个事务读到了另一个事务已经提交的(insert)数据.导致多次查询的结果不一致

  • 设置事务的隔离级别:

  1. read uncommitted :脏读,不可重复读,虚读都可能发生.

  2. read committed :避免脏读,但是不可重复读和虚读有可能发生.(Oracle默认)

  3. repeatable read :避免脏读和不可重复读,但是虚读有可能发生的(MySql默认)

  4. serializable :避免脏读,不可重复读和虚读.(串行化的-不可能出现事务并发访问)

  • 使用JDBC进行隔离级别的设置

    1. void setTransactionIsolation(int level):视图将此Connection对象的事务隔离级别更改为给定的级别
    2. static int TRANSACTION_NONE:指示事务不受支持的常量
    3. static int TRANSACTION_READ_COMMITTED 指示不可以发生脏读的常量;不可重复读和虚读可以发生
    4. static int TRANSACTION_READ_UNCOMMITTED:指示可以发生脏读,不可重复读和虚读的常量
    5. static int TRANSACTION_REPEATABLE_READ:指示不可以发生脏读和不可重复读的常量,虚读可以发生
    6. static int TRANSACTION_SERTALIZABLE:指示不可以发生脏读 不可重复度和虚读的常量

案例2:商品信息储存

  • 首先使用mvc思想进行设计,我设计的内容框架是这样的

    1. 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 findAll() throws SQLException{
              ProductDao dao = new ProductDao();
              List 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 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();
              }
          }
      }
      
      
    2. 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;
          }
      }
      
      
    3. 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 findAll() throws SQLException{
              ProductDao dao = new ProductDao();
              List 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 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();
              }
          }
      }
      
      
    4. 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 tl = new ThreadLocal();
          //获取连接
          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();
          }
      }
      
      
    5. 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 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 ps = service.findAll();
            if (ps == null)
                System.out.println("您的仓库里面没有商品");
            else {
                    for (Product p : ps) {
                        System.out.println(p);
                    }
                    System.out.println("查询商品成功");
            }
        }
    }
    
    

总结

  • SQL语句:

    1. DDL:数据库定义语言:数据库定义语言,主要对数据库,表,列进行增删改查

      1. 创建数据库:create database 数据名(charset 字符集名)
      2. 创建表: create table 表名:(字段名 数据类型 长度 )
      3. SQL中的数据类型:整数:int 小数:double 字符串:varchar()长度,建议使用2的整数倍,日期?格式’yyyy-mm-dd’
      4. 主键约束primary key 唯一且非空,自动增长列约束auto_increment,必须是数值类型,而且一般我们会给主键加上自增长约束,唯一约束unique,多个记录的该列的值不能相同,非空约束not null不能为空,默认约束default,默认约束,为某一个字段设置默认值,外键约束foreign key多表查询
    2. DCL:数据库控制语言

    3. DML:数据库操作语言:

      1. insert into 表名 (字段…) values (值1,2,3)
      2. 注意事项,字段与值要一一对应,如果是全字段,表名后面可以不写,但是values必须写上全部字段的值,值的写法,除了数值类型的值,其他类型的值必须用’'或者""括起来
      3. 删除: delete from 表明(where 条件) trancate table表明:以上两种删除表的区别,delete:只会删除记录,不会重置自动增长集,trancate:摧毁表,再重建,即会删除所有记录,也会重置自动增长值
    4. DQL:数据库查询语言

      1. 单表查询: 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 表
        
        
        
      2. 多表查询:

        一对多:必须两张表,一张主表,一张从表;
          原则:从表必须有一个外键,这个外间引用主表的主键
          添加外检约束: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
        
        

你可能感兴趣的:(学生,java,jdbc-案例加解析,java_08JDBC)