zoukankan      html  css  js  c++  java
  • JDBC第二次学习

       脑子太笨,必须得记录下来一些文字,方便回来查询。

       这是我的第二次学习JDBC的笔记,看的是传智播客——李勇老师的JDBC系列,已看到第23集。

       分析在实际项目中该如何应用JDBC

       一个简单用户相关的数据访问层

    1. J2EE三层架构简介:表示层 、业务逻辑层、数据访问层,三层之间用接口隔离。
    2. 定义domain对象User,定义存取用户的接口。

    3. 用JDBC实现接口。

    4. 用配置文件(properties)和反射实现与具体类的耦合。

       用图来表示:

       

       在真实的项目开发中,我们能不能返回ResultSet对象呢? 如下例代码:

    static ResultSet read() throws SQLException {
            Connection conn = null;
            Statement st = null;
            ResultSet rs = null;
            try {
                //2.建立连接
                conn = JdbcUtils.getConnection();
                //3.创建语句
                st = conn.createStatement();
                //4.执行语句
                rs = st.executeQuery("select id,name,birthday,money from user");
                //5.处理结果
                while(rs.next()) {
                    System.out.println(rs.getObject("id")+"	"+rs.getObject("name")+
                            "	"+rs.getObject("birthday")+"	"+rs.getObject("money"));
                }
                return rs;//连接关闭,Statement、ResultSet都失效了。
            } finally {
                JdbcUtils.free(rs, st, conn);
            }
        }

       在main()方法中调用:

    ResultSet rs = read();
    

       这个其实是不可以的,当Connection关闭之后,ResultSet中的数据你就拿不到了(Statement、ResultSet都失效了)。如果我们要进行传值需要定义个domain对象。 

       我们重点关注数据访问层的代码如何书写

       1、定义domain对象User以及存取用户的接口:

    import cn.itcast.jdbc.domain.User;
    
    public interface UserDao {
        public void addUser(User user);
        
        public User getUser(int userId);
        
        public User findUser(String loginName, String password);
        
        public void update(User user);
        
        public void delete(User user);
    }
    import java.util.Date;
    
    public class User {
        private int id;
        private String name;
        private Date birthday;
        private float money;
        
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Date getBirthday() {
            return birthday;
        }
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
        public float getMoney() {
            return money;
        }
        public void setMoney(float money) {
            this.money = money;
        }
        
    }

       2、用JDBC实现接口。在实现的过程中,准确一点说会出现SQLException。关于这个异常的处理,很多工作2年的程序员都不知道怎么样处理,所以对于此异常,定当重视,通常我们结合Service层讲解DAO层的异常处理的方式。

       就拿addUser(user)方法来说,中间是有可能出现SQLException的,在处理异常的时候,不能catch住异常之后什么都不做,最起码要打印一下堆栈,最好的方式是将这个异常转化为RuntimeException抛出。做法如下:

       建立一个DaoException继承RuntimeException,如下: 

    public class DaoException extends RuntimeException {
    
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
    
        public DaoException() {
            // TODO Auto-generated constructor stub
        }
    
        public DaoException(String message) {
            super(message);
            // TODO Auto-generated constructor stub
        }
    
        public DaoException(Throwable cause) {
            super(cause);
            // TODO Auto-generated constructor stub
        }
    
        public DaoException(String message, Throwable cause) {
            super(message, cause);
            // TODO Auto-generated constructor stub
        }
    
        public DaoException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
            super(message, cause, enableSuppression, writableStackTrace);
            // TODO Auto-generated constructor stub
        }
    
    }

       之后JDBC实现接口的过程中,就抛出DaoException异常,如下(代码太多,折叠之):

    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    import cn.itcast.jdbc.JdbcUtils;
    import cn.itcast.jdbc.dao.DaoException;
    import cn.itcast.jdbc.dao.UserDao;
    import cn.itcast.jdbc.domain.User;
    
    public class UserDaoJdbcImpl implements UserDao {
    
        @Override
        public void addUser(User user) {
            Connection conn = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                //2.建立连接
                conn = JdbcUtils.getConnection();
                //3.创建语句
                String sql = "insert into user (name,birthday,money) values (?,?,?)";
                ps = conn.prepareStatement(sql);
                ps.setString(1, user.getName());
                ps.setDate(2, new java.sql.Date(user.getBirthday().getTime()));
                ps.setFloat(3, user.getMoney());
                //4.执行语句
                ps.executeUpdate();
            } catch(SQLException e) {
                throw new DaoException(e.getMessage(), e);
            } finally {
                JdbcUtils.free(rs, ps, conn);
            }
        }
    
        @Override
        public User getUser(int userId) {
            Connection conn = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            User user = null;
            try {
                //2.建立连接
                conn = JdbcUtils.getConnection();
                //3.创建语句
                String sql = "select id,name,birthday,money from user where id = ?";
                ps = conn.prepareStatement(sql);
                ps.setInt(1, userId);
                //4.执行语句
                rs = ps.executeQuery();
                //5.处理结果
                while(rs.next()) {
                    /*
                     * 优化①处
                     */
                    user = mappingUser(rs);
                }
            } catch(SQLException e) {
                throw new DaoException(e.getMessage(), e);
            } finally {
                JdbcUtils.free(rs, ps, conn);
            }
            return user;
        }
    
        @Override
        public User findUser(String loginName, String password) {
            Connection conn = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            User user = null;
            try {
                //2.建立连接
                conn = JdbcUtils.getConnection();
                //3.创建语句
                String sql = "select id,name,birthday,money from user where name = ?";
                ps = conn.prepareStatement(sql);
                ps.setString(1, loginName);
                //4.执行语句
                rs = ps.executeQuery();
                //5.处理结果
                while(rs.next()) {
                    /*
                     * 优化①处
                     */
                    user = mappingUser(rs);
                }
            } catch(SQLException e) {
                throw new DaoException(e.getMessage(), e);
            } finally {
                JdbcUtils.free(rs, ps, conn);
            }
            return user;
        }
        
        private User mappingUser(ResultSet rs) throws SQLException {
            User user = new User();
            user.setId(rs.getInt("id"));
            user.setName(rs.getString("name"));
            user.setMoney(rs.getFloat("money"));
            user.setBirthday(rs.getDate("birthday"));
            return user;
        }
        
    
        @Override
        public void update(User user) {
            Connection conn = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                //2.建立连接
                conn = JdbcUtils.getConnection();
                //3.创建语句
                String sql = "update user set name = ?,birthday = ?,money = ? where id = ?";
                ps = conn.prepareStatement(sql);
                ps.setString(1, user.getName());
                ps.setDate(2, new java.sql.Date(user.getBirthday().getTime()));
                ps.setFloat(3, user.getMoney());
                ps.setInt(4, user.getId());
                //4.执行语句
                ps.executeUpdate();
            } catch(SQLException e) {
                throw new DaoException(e.getMessage(), e);
            } finally {
                JdbcUtils.free(rs, ps, conn);
            }
        }
    
        @Override
        public void delete(User user) {
            Connection conn = null;
            Statement st = null;
            ResultSet rs = null;
            try {
                //2.建立连接
                conn = JdbcUtils.getConnection();
                //3.创建语句
                st = conn.createStatement();
                //4.执行语句
                String sql = "delete from user where id = "+user.getId();
                st.executeUpdate(sql);
            } catch(SQLException e) {
                throw new DaoException(e.getMessage(), e);
            } finally {
                JdbcUtils.free(rs, st, conn);
            }
        }
    
    }
    View Code

       用配置文件(properties)和反射实现与具体类的耦合(?),此时就要用到工厂模式了。

       DaoFactory类如下(视频说代码很经典,谁知道呢?)

    import java.io.InputStream;
    import java.util.Properties;
    
    public class DaoFactory {
        /*
         * 注意两个static属性之间的顺序
         * 如果搞反,那么属性userDao始终为空!
         */
        private static UserDao userDao = null;
        private static DaoFactory instance = new DaoFactory();
        
        private DaoFactory() {
            try {
                Properties prop = new Properties();
                
                /*
                 * 方式一
                 * 缺点:路径是写死的,如果我们的配置文件改变了地方,就找不到文件了 。
                 */
                //FileInputStream fis = new FileInputStream("src/daoconfig.properties");
                
                /*
                 * 方式二
                 * 优点:用类加载器(马丹,涉及到反射技术,又是一个要补的地方)的方法
                 * 来得到一个文件的输入流,只要这个文件在classpath路径下(其实编译的xxx.class文件和配置文件
                 * 就在根目录下bin目录中,而次bin目录被自动加载到classpath变量值中(别问我why?我也不知道))就能找到。
                 */
                InputStream fis = DaoFactory.class.getClassLoader()//类加载器(???)
                        .getResourceAsStream("daoconfig.properties");//daoconfig.properties只要在classpath路径下,就可以加载进来,更加灵活
                prop.load(fis);
                String userDaoClass = prop.getProperty("userDaoClass");
                /*
                 * 涉及到反射技术
                 */
                Class clazz = Class.forName(userDaoClass);//将类加载到JVM
                userDao = (UserDao)clazz.newInstance();//实例化一个对象
                //System.out.println(userDao);
            } catch (Throwable e) {
                throw new ExceptionInInitializerError(e);
            }
            
        }
        public static DaoFactory getInstance() {
            return instance;
        }
        
        public UserDao getUserDao() {
            //System.out.println(userDao);
            return userDao;
        }
    }

       整体的框架图应该如这幅模样:

       

       

       JDBC事务处理

       关于事务,我已经在《浅谈事务》一文中详细记录过,在此不赘述了。我们只关注JDBC是如何处理事务的。

       示例1(用代码来体现):

    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    public class TxIsolateTest {
        public static void main(String[] args) throws SQLException {
            test();
        }
        
        static void test() throws SQLException {
            Connection conn = null;
            Statement st = null;
            ResultSet rs = null;
            try {
                conn = JdbcUtils.getConnection();
                /*
                 * 设置事务为手动提交,一说也叫打开事务。
                 */
                conn.setAutoCommit(false);
                /*
                 * 设置事务的隔离级别,这是一个超麻烦的问题,李勇老师也是敷衍过去!
                 */
                conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
                
                String sql = "update user set money = money - 10 where id = 1";
                st = conn.createStatement();
                st.executeUpdate(sql);
                
                sql = "select money from user where id = 2";
                rs = st.executeQuery(sql);
                float money = 0.0f;
                if(rs.next()) {
                    money = rs.getFloat("money");
                }
                if(money > 400)
                    throw new RuntimeException("已经超过最大值!");
                sql = "update user set money = money + 10 where id = 2";
                st.executeUpdate(sql);
                /*
                 * 提交事务
                 */
                conn.commit();
            } catch (SQLException e) {
                if(conn != null)
                    /*
                     * 回滚事务,rollback()中不加任何参数,即为回滚所有操作
                     */
                    conn.rollback();
                throw e;
            } finally {
                JdbcUtils.free(rs, st, conn);
            }
        }
    }

       示例2:

    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Savepoint;
    import java.sql.Statement;
    
    public class SavePointTest {
        public static void main(String[] args) throws SQLException {
            test();
        }
        
        static void test() throws SQLException {
            Connection conn = null;
            Statement st = null;
            ResultSet rs = null;
            Savepoint sp = null;
            try {
                conn = JdbcUtils.getConnection();
                conn.setAutoCommit(false);
                st = conn.createStatement();
                String sql = "update user set money = money - 10 where id = 1";
                st.executeUpdate(sql);
                /*
                 * 设置保存点
                 */
                sp = conn.setSavepoint();
                
                sql = "update user set money = money - 10 where id = 3";
                st.executeUpdate(sql);
                
                sql = "select money from user where id = 2";
                rs = st.executeQuery(sql);
                float money = 0.0f;
                if(rs.next()) {
                    money = rs.getFloat("money");
                }
                if(money > 300)
                    throw new RuntimeException("已经超过最大值!");
                sql = "update user set money = money + 10 where id = 2";
                st.executeUpdate(sql);
                conn.commit();
            } catch (RuntimeException e) {
                if(conn != null && sp != null) {
                    conn.rollback(sp);//回滚到保存点上去,再提交,这样保证到保存点之前那些操作都是有效的(只回滚一部分操作)
                    conn.commit();
                }
                throw e;
            } catch (SQLException e) {
                if(conn != null)
                    conn.rollback();
                throw e;
            } finally {
                JdbcUtils.free(rs, st, conn);
            }
        }
    }

       JTA分布式事务的简要介绍(李勇老师也是敷衍过去了)

       跨越多个数据源的事务,使用JTA容器(是啥,不知道?)实现事务。 

       分成两阶段提交。 

       代码格式总是如此:

    javax.transaction.UserTransaction tx = (UserTransaction)ctx.lookup(“jndi(?)Name");  
    tx.begin();  
    //connection1 connection2 (可能来自不同的数据库)…   
    tx.commit();//tx.rollback();  

       

       

  • 相关阅读:
    Python正课101 —— 前端 入门
    Python正课100 —— 数据库 进阶5
    Python正课99 —— 数据库 进阶4
    Navicat15安装教程
    Python正课98 —— 数据库 进阶3
    Python正课97 —— 数据库 进阶2
    Python正课96 —— 数据库 进阶1
    解决:MySQL报错
    Python正课95 —— 数据库 入门
    作业3
  • 原文地址:https://www.cnblogs.com/yerenyuan/p/5323574.html
Copyright © 2011-2022 走看看