博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
javaEE(13)_jdbc框架
阅读量:6714 次
发布时间:2019-06-25

本文共 15504 字,大约阅读时间需要 51 分钟。

一、使用模板方法设计模式简化开发

模板方法设计模式,执行一个程序有很多步骤,将每次都要执行的共有的提取出来放到一个抽象父类中,变化的部分通过让子类传递参数过来或将这部分抽象为抽象方法让子类通过继承的方式去实现.

我们的UserDaoJdbcImpl 有大量重复的代码,使用模板设计模式重构如下:

//定义抽象类,提取公共部分public abstract class AbstractDao { // 查    public Object find(String sql, Object[] args) {        Connection conn = null;        PreparedStatement ps = null;        ResultSet rs = null;        Object obj = null;        try {            conn = JdbcUtils.getConnection();            ps = conn.prepareStatement(sql);            for (int i = 0; i < args.length; i++) {                ps.setObject(i + 1, args[i]);            }            rs = ps.executeQuery();            while (rs.next()) {                obj = rowMapper(rs);            }        } catch (SQLException e) {            throw new DaoException(e.getMessage(), e);        } finally {            JdbcUtils.free(rs, ps, conn);        }        return obj;    }    // 将变化的部分,让子类去实现    public abstract Object rowMapper(ResultSet rs);      //增删改    public void update(String sql, Object[] args) {        Connection conn = null;        PreparedStatement ps = null;        ResultSet rs = null;        try {            conn = JdbcUtils.getConnection();            ps = conn.prepareStatement(sql);            for (int i = 0; i < args.length; i++) {                ps.setObject(i + 1, args[i]);            }        } catch (SQLException e) {            throw new DaoException(e.getMessage(), e);        } finally {            JdbcUtils.free(rs, ps, conn);        }    }}
public class UserDaoImpl extends AbstractDao implements UserDao{            public void update(User user) {            String sql = "update user set name=?, birthday=?, money=? where id=? ";            Object[] args = new Object[] { user.getName(), user.getBirthday(),                    user.getMoney(), user.getId() };            super.update(sql, args);        }            public User findUser(String loginName, String password) {            String sql = "select id, name, money, birthday  from user where name=?";            Object[] args = new Object[] { loginName };            Object user = super.find(sql, args);            return (User) user;        }                public Object rowMapper(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;        }}

这种方式有一个问题就是UserDaoImp类中只能有一个rowMapper方法,如果还有一个查询方法要映射,则无法实现只能在写一个类,相当不灵活.既然变化的sql和参数可以从子类传递那么映射也可以传递,结合策略模式重构上面代码如下.

二、使用策略模式对模板方法设计模式进行改进

//没有抽象方法了,也没有必要定义为抽象类public class MyTemplete {    //RowMapper定义为一个接口,可以有不同的实现,相当于不同的策略    public Object find(String sql,Object[] args,RowMapper rowMapper) {        Connection conn = null;        PreparedStatement ps = null;        ResultSet rs = null;        Object obj = null;        try {            conn = JdbcUtils.getConnection();            ps = conn.prepareStatement(sql);            for(int i=0;i
public class UserDaoImpl  implements UserDao{        MyTemplete myTemplete = new MyTemplete(); //定义一个模板        public User findUser(String loginName, String password) {            String sql = "select id, name, money, birthday  from user where name=?";            Object[] args = new Object[] { loginName };            Object user = myTemplete.find(sql, args,new RowMapper(){                @Override                public Object rowMapper(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;                }            });            return (User) user;        }}

三、Apache—DBUtils框架

commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能.因此dbutils成为很多不喜欢hibernate的公司的首选.
//使用dbutils完成数据库的crudpublic class Demo1 {        @Test    public void insert() throws SQLException{        QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());        String sql = "insert into users(id,name,password,email,birthday) values(?,?,?,?,?)";        Object params[] = {
2,"bbb","123","aa@sina.com",new Date()}; runner.update(sql, params); } @Test public void update() throws SQLException{ QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource()); String sql = "update users set email=? where id=?"; Object params[] = {
"aaaaaa@sina.com",1}; runner.update(sql, params); } @Test public void delete() throws SQLException{ QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource()); String sql = "delete from users where id=?"; runner.update(sql, 1); } @Test public void find() throws SQLException{ QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource()); String sql = "select * from users where id=?"; User user = (User) runner.query(sql, 1, new BeanHandler(User.class)); System.out.println(user.getEmail()); } @Test public void getAll() throws Exception{ QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource()); String sql = "select * from users"; List list = (List) runner.query(sql, new BeanListHandler(User.class)); System.out.println(list); } @Test public void batch() throws SQLException{ QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource()); String sql = "insert into users(id,name,password,email,birthday) values(?,?,?,?,?)"; Object params[][] = new Object[3][5]; for(int i=0;i
//测试dbutils的各个结果集处理器,只是一部分public class Demo2 {        @Test    public void test1() throws SQLException{        QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());        String sql = "select * from users";        Object result[] = (Object[]) runner.query(sql, new ArrayHandler());        System.out.println(result[0]);        System.out.println(result[1]);    }        @Test    public void test2() throws SQLException{        QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());        String sql = "select * from users";        List list = (List) runner.query(sql, new ArrayListHandler());        System.out.println(list);    }        @Test    public void test3() throws SQLException{        QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());        String sql = "select * from users";        List list = (List) runner.query(sql, new ColumnListHandler1("name"));        System.out.println(list);    }}

ps:采用DBUtils后,jdbcUtils工具类中获取连接和释放连接的方法也不需要了,只需提供获取数据源的方法(如果进行做事务处理还需要).

四、jdbc应用事务管理

1、使用如上所示的jdbcUtils时,我们无需管理连接的获取和关闭,在每次进行完一条sql的执行后连接会自动归还连接池.但是要进行事务处理的话就要手动获取和关闭连接,因为同一个事务必须使用同一个数据库连接,转账案例dao层代码如下:

//从a--->b帐户转100元public void transfer() throws SQLException{    Connection conn = null;    try{        conn = JdbcUtils.getConnection();//连接池中获取连接        conn.setAutoCommit(false);                QueryRunner runner = new QueryRunner();        String sql1 = "update account set money=money-100 where name='aaa'";        runner.update(conn,sql1);                String sql2 = "update account set money=money+100 where name='bbb'";        runner.update(conn,sql2);                conn.commit();    }finally{        if(conn!=null){            conn.close();//连接放回连接池        }    }}

ps:dao层做事务管理的话就把业务逻辑放在了dao层,违背三层架构设计思想,dao层只能做简单的增删改查,于是要将事务管理放在service层,代码如下:

public void transfer1(int sourceid,int targetid,double money) throws SQLException{        Connection conn = null;    try{        conn = JdbcUtils.getConnection();        conn.setAutoCommit(false);                AccountDao dao = new AccountDao(conn); //把当前conn传递给dao         Account a = dao.find(sourceid);   //select        Account b = dao.find(targetid);   //select        a.setMoney(a.getMoney()-money);          b.setMoney(b.getMoney()+money);           dao.update(a); //update        dao.update(b);//update                conn.commit();    }finally{        if(conn!=null) conn.close();    }}

2、更优雅的做法,使用ThreadLocal(*重要),ThreadLocal可以实现线程内的数据共享,ThreadLocal其实是一个大大的Map集合,set方法就是往map集合中存数据,map的key是当前线程的名称,ThreadLocal API如下,只有三个方法:

T get()      Returns the value in the current thread's copy of this thread-local variable.void remove()     Removes the current thread's value for this thread-local variable.void set(T value) Sets the current thread's copy of this thread-local variable to the specified value.

使用ThreadLocal后代码如下:

//QueryRunner 的各种更新和查询可以接收一个数据库连接,简直就是为事务处理设置的,不处理事务没必要传连接public class AccountDao {    private Connection conn;    public AccountDao(Connection conn) {        this.conn = conn;    }    public void update(Account a) {        try {            QueryRunner runner = new QueryRunner();            String sql = "update account set money=? where id=?";            Object params[] = { a.getMoney(), a.getId() };            runner.update(JdbcUtils.getConnection(), sql, params);        } catch (Exception e) {            throw new RuntimeException(e);        }    }    public Account find(int id) {        try {            QueryRunner runner = new QueryRunner();            String sql = "select * from account where id=?";            return (Account) runner.query(JdbcUtils.getConnection(), sql, id,                    new BeanHandler(Account.class));        } catch (Exception e) {            throw new RuntimeException(e);        }    }}
//用上ThreadLocal的事务管理public void transfer2(int sourceid,int targetid,double money) throws SQLException{    try{        JdbcUtils.startTransaction();        AccountDao dao = new AccountDao();        Account a = dao.find(sourceid);   //select        Account b = dao.find(targetid);   //select        a.setMoney(a.getMoney()-money);          b.setMoney(b.getMoney()+money);           dao.update(a); //update        dao.update(b);//update        JdbcUtils.commitTransaction();    }finally{        JdbcUtils.closeConnection();    }}
public class JdbcUtils {    private static DataSource ds;    static {        try {            Properties prop = new Properties();            InputStream in = JdbcUtils.class.getClassLoader()                    .getResourceAsStream("dbcpconfig.properties");            prop.load(in);            BasicDataSourceFactory factory = new BasicDataSourceFactory();            ds = factory.createDataSource(prop);        } catch (Exception e) {            throw new ExceptionInInitializerError(e);        }    }    public static DataSource getDataSource() {        return ds;    }    // 不进行事务处理的话上面的代码就够了,下面用来进行事务处理    private static ThreadLocal
tl = new ThreadLocal
(); public static Connection getConnection() throws SQLException { try { // 得到当前线程上绑定的连接 Connection conn = tl.get(); if (conn == null) { // 代表线程上没有绑定连接 conn = ds.getConnection(); tl.set(conn); } return conn; } catch (Exception e) { throw new RuntimeException(e); } } public static void startTransaction() { try { // 得到当前线程上绑定连接开启事务 Connection conn = tl.get(); if (conn == null) { // 代表线程上没有绑定连接 conn = ds.getConnection(); tl.set(conn); } conn.setAutoCommit(false); } catch (Exception e) { throw new RuntimeException(e); } } public static void commitTransaction() { try { Connection conn = tl.get(); if (conn != null) { conn.commit(); } } catch (Exception e) { throw new RuntimeException(e); } } public static void closeConnection() { try { Connection conn = tl.get(); if (conn != null) { conn.close(); } } catch (Exception e) { throw new RuntimeException(e); } finally { tl.remove();// 千万注意,解除当前线程上绑定的链接(从threadlocal容器中移除对应当前线程的链接) } }}

ps:ThreadLocal用处很多,很多框架中使用它存储对象,比如现在servlet中使用外部定义的对象可以有三种方式,通过参数传递给它,通过JNDI容器,通过ThreadLocal.

五、servlet层事务管理

1、如果service层事务管理不能满足需求,需要在servlet层进行事务处理,使用如上代码也可实现,将JdbcUtils.startTransaction(); JdbcUtils.commitTransaction(); JdbcUtils.closeConnection();放在servlet中即可.

2、如果单servlet也不能满足需求,比如实现servlet转发后还需要事务处理,则要可以使用Filter,在Filter中给ThreadLocal绑定连接.

ps:也就是实现jdbc事务必须使用同一个数据库连接,只需要将ThreadLocal与数据库连接的绑定往上层提即可.

***事务的处理使用springJDBC好像比较方便,以后再看.

六、jdbc多表操作

1、员工和部门是一对多的关系,老师和学生是多对多的关系,设计表的时候一定要注意.如下老师学生代码:

public void add(Teacher t) throws SQLException {        QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());        //1`.取出老师存老师表    String sql = "insert into teacher(id,name,salary) values(?,?,?)";    Object params[] = {t.getId(),t.getName(),t.getSalary()};    runner.update(sql, params);        //2.取出老师所有学生的数据,存学生表    Set
set = t.getStudents(); for(Student s : set){ sql = "insert into student(id,name) values(?,?)"; params = new Object[]{s.getId(),s.getName()}; runner.update(sql, params); //3.更新中间表,说明老师和学生的关系 sql = "insert into teacher_student(teacher_id,student_id) values(?,?)"; params = new Object[]{t.getId(),s.getId()}; runner.update(sql, params); }}

推理:这段代码必须要加事务处理,那么在dao层中又加入了逻辑代码,所以应该将这段代码在dao层中分开写,在service层中进行事务处理.

七、springJDBC使用

public class JdbcTemplateTest {    static JdbcTemplate jdbc = new JdbcTemplate(JdbcUtils.getDataSource());    //查询    static User findUser(String name) {        String sql = "select id, name, money, birthday  from user where name=?";        Object[] args = new Object[] { name };        Object user = jdbc.queryForObject(sql, args, new RowMapper() {            public Object mapRow(ResultSet rs, int rowNum) 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;            }        });        return (User) user;    }    //BeanPropertyRowMapper利用原数据和反射直接封装到User中    static User findUser1(String name) {        String sql = "select id, name, money, birthday  from user where name=?";        Object[] args = new Object[] { name };        Object user = jdbc.queryForObject(sql, args, new BeanPropertyRowMapper(                User.class));        return (User) user;    }    //特殊的跟新要拿到插入的组建,其它正常更新略    static int addUser(final User user) {        jdbc.execute(new ConnectionCallback() {            public Object doInConnection(Connection con) throws SQLException,                    DataAccessException {                String sql = "insert into user(name,birthday, money) values (?,?,?) ";                PreparedStatement ps = con.prepareStatement(sql,                        Statement.RETURN_GENERATED_KEYS);                ps.setString(1, user.getName());                ps.setDate(2, new java.sql.Date(user.getBirthday().getTime()));                ps.setFloat(3, user.getMoney());                ps.executeUpdate();                ResultSet rs = ps.getGeneratedKeys();                if (rs.next())                    user.setId(rs.getInt(1));                return null;            }        });        return 0;    }}

ps:以后补充springJDBC.

转载于:https://www.cnblogs.com/wangweiNB/p/5067757.html

你可能感兴趣的文章
Order By操作
查看>>
(三)mybatis之对Hibernate初了解
查看>>
nginx安装与配置
查看>>
Android 命令设置获取、IP地址、网关、dns
查看>>
查找当前薪水(to_date='9999-01-01')排名第二多的员工编号emp_no、薪水salary、last_name以及first_name,不准使用order by...
查看>>
[SQL in Azure] Windows Azure Virtual Machine Readiness and Capacity Assessment
查看>>
关于CCR测评器的自定义校验器(Special Judge)
查看>>
java设计模式之 装饰器模式
查看>>
利息力(force of interest)
查看>>
Oracle 角色及其权限
查看>>
NiftyDialogEffects:集成了多种动画效果的Dialog控件
查看>>
《世界是数字的》读后感
查看>>
AD软件原理图封装过程(即由原理图转换到PCB)
查看>>
cocos2d-x lua table与json的转换
查看>>
mysql的基本原理
查看>>
《面向对象分析与设计》——抽象
查看>>
linux学习记录-------jdk安装配置
查看>>
查看dll依赖项
查看>>
koa和egg项目webpack热更新实现
查看>>
ansible普通用户su切换问题
查看>>