JDBC(2)JAVA连接数据库之 分页操作、事务操作、代理模式

来源:互联网 发布:gossip协议《算法》 编辑:程序博客网 时间:2024/06/04 00:27

分页操作(排序)

与表相对应的用户类

package lesson2;public class User {    private int id;    private String username;    private String userpass;    private String email;    public User (){}    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public String getUserpass() {        return userpass;    }    public void setUserpass(String userpass) {        this.userpass = userpass;    }    public String getEmail() {        return email;    }    public void setEmail(String email) {        this.email = email;    }    public User(int id, String username, String userpass, String email) {        super();        this.id = id;        this.username = username;        this.userpass = userpass;        this.email = email;    }    @Override    public String toString() {        return "User [id=" + id + ", username=" + username + ", userpass="                + userpass + ", email=" + email + "]";    }}

与表相关操作的包装类(UserDao)

package lesson2;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.util.ArrayList;import java.util.List;/** * 分页操作 * @author hh * */public class UserDao {    public List<User> findByPage(int page,int pageSize){        Connection con = null;        PreparedStatement pstmt = null;        ResultSet rs = null;        List<User> users = new ArrayList<User>();        try {            con = JdbcUitl.getConn();            int begin=(page-1)*pageSize+1;            int end = page*pageSize;             String sql="select id,username,userpass,email from" +                    "(select id,username,userpass,email,rownum rn from bb_user order by id)" +                    "where rn between ? and ?";            pstmt = con.prepareStatement(sql);            pstmt.setInt(1, begin);            pstmt.setInt(2, end);            rs=pstmt.executeQuery();            while(rs.next()){                User user = new User();                user.setId(rs.getInt("id"));                user.setUsername(rs.getString("username"));                user.setUserpass(rs.getString("userpass"));                user.setEmail(rs.getString("email"));                users.add(user);            }        } catch (Exception e) {            e.printStackTrace();        }finally{            JdbcUitl.close(pstmt, rs);        }        return users;    }}

测试类

package lesson2;import java.util.ArrayList;import java.util.List;public class JdbcDemo1 {    public static void main(String[] args) {        UserDao ud = new UserDao();        List<User> users =ud.findByPage(1,5);        for (User user : users) {            System.out.println(user);        }    }}

事务

  • 创建一张表
  • 把表相关的操作封装
  • 只有提交事务之后,jabc才能操作数据
    • commit 提交 rollback 回滚
  • Connection 对象默认操作完后提交事务。
  • 如果不要自动提交,需要操作:con.setAutoCommit(false);

创建新的测试表格account 创建与之对应的数据类

package lesson2;public class Account {    private int id;    private int money;    private String name;    public Account(){}    public Account(int id, int money, String name) {        super();        this.id = id;        this.money = money;        this.name = name;    }    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public int getMoney() {        return money;    }    public void setMoney(int money) {        this.money = money;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    @Override    public String toString() {        return "Account [id=" + id + ", money=" + money + ", name=" + name                + "]";    }}

与表相关操作的包装类(AccountDao)

这可以看到没有关闭Connection对象,是为了后面的事务操作

package lesson2;import java.nio.Buffer;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.PseudoColumnUsage;import java.sql.ResultSet;import java.util.ArrayList;import java.util.List;import oracle.net.aso.p;public class AccountDao {    public int addAccount(Account account){        Connection con = null;        PreparedStatement pstmt = null;        int n = 0;        try {            con = JdbcUitl.getConn();            pstmt = con.prepareStatement("insert into account(id,money,name)values(?,?,?)");            pstmt.setInt(1, account.getId());            pstmt.setInt(2, account.getMoney());            pstmt.setString(3, account.getName());            n=pstmt.executeUpdate();        } catch (Exception e) {            e.printStackTrace();        }finally{            JdbcUitl.close(pstmt, null);        }        return n;    }    public Account findById(int id){        Connection con = null;        PreparedStatement pstmt = null;        ResultSet rs = null;        Account account = null;        try {            con = JdbcUitl.getConn();            pstmt=con.prepareStatement("select * from account where id="+id);            rs = pstmt.executeQuery();            if(rs.next()){                account = new Account();                account.setId(rs.getInt("id"));                account.setMoney(rs.getInt("money"));                account.setName(rs.getString("name"));            }        } catch (Exception e) {            e.printStackTrace();        }finally{            JdbcUitl.close(pstmt, rs);        }        return account;    }    public List<Account> getllAccount(){        Connection con = null;        PreparedStatement pstmt = null;        ResultSet rs = null;        List<Account> accounts = new ArrayList<Account>();        try {            con = JdbcUitl.getConn();            pstmt = con.prepareStatement("select id,money,name from account");            rs = pstmt.executeQuery();            while(rs.next()){                Account account = new Account();                account.setId(rs.getInt("id"));                account.setMoney(rs.getInt("money"));                account.setName(rs.getString("name"));                accounts.add(account);            }        } catch (Exception e) {            e.printStackTrace();        }finally{            JdbcUitl.close(pstmt, rs);        }        return accounts;    }    public int updateAccount(int id,int money){        Connection con = null;        PreparedStatement pstmt = null;        int n = 0;        try {            con = JdbcUitl.getConn();            String sql = "update account set money = ? where id=?";            pstmt = con.prepareStatement(sql);            pstmt.setInt(1, money);            pstmt.setInt(2, id);            n=pstmt.executeUpdate();        } catch (Exception e) {            e.printStackTrace();        }finally{            JdbcUitl.close(pstmt,null);        }        return n;    }}

测试类

package lesson2;import java.util.List;public class JdbcDemo2 {    public static void main(String[] args) {        AccountDao ad = new AccountDao();        //查询全部记录/*      List<Account> accounts = ad.getllAccount();        for (Account account : accounts) {            System.out.println(account);        } */        //修改记录/*      int n = ad.updateAccount(1002, 300);        System.out.println(n);        */        //根据主键查询        Account account = ad.findById(1001);        System.out.println(account);    }}
  • 数据层:关于数据库的操作 ,增删改查
  • 业务层:正常的业务处理 比如转账业务(A—>B):修改两次数据操作。也有可能和数据层无关
  • 完成转账操作
    • A转账给B 这个过程A减少钱,若果B出意外了。所以两个操作放在一个事物中,而connection中,默认自动提交。
    • 要在同一个事物中操作,就必须多个关于数据的操作必须是同一个连接,要保证同一个线程中是同一个connection。
    • 修改 JdbcUtil threadLocal
    • Connection 的关闭,必须在一个业务操作完成之后,进行关闭。
  • 业务处理开始之前,开启事物,业务处理之后提交事物,业务处理有异常 回滚事物,左后关闭connection
  • 将来会有,一个业务操作一组dao, 我们就是需要把多个业务包装到一个dao中,要么全成功,要么全全失败、
  • 但是每个业务都这样写,比较繁琐。我们希望利用代理的方式。

JdbcUitl类

保证同一个线程中是同一个connection。方面后面的事务操作

package lesson2;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.util.Properties;public class JdbcUitl {    private static Properties prop = new Properties();    private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();    static{        try {            prop.load(JdbcUitl.class.getResourceAsStream("/database.properties"));        } catch (Exception e) {            e.printStackTrace();        }    }    public static Connection getConn(){        //保证同一个线程中是同一个connection        Connection con = tl.get();        try {            if(con==null){                Class.forName(prop.getProperty("driverClass"));                con = DriverManager.getConnection(                        prop.getProperty("url"),prop.getProperty("user"),prop.getProperty("pass"));                tl.set(con);            }            return tl.get();        } catch (Exception e) {            e.printStackTrace();            return null;        }    }    /**     * 资源关闭     * @param con     * @param stmt     * @param rs     */    public static void close(Statement stmt,ResultSet rs){        if(rs!=null)            try {                rs.close();            } catch (Exception e) {                e.printStackTrace();            }        if(stmt!=null)            try {                stmt.close();            } catch (SQLException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }    }    public static void closeConnection(){        Connection con = tl.get();        if(con!=null){            try {                con.close();                tl.remove();            } catch (Exception e) {                e.printStackTrace();            }        }    }}

业务类

手动抛出异常,测试可以发现,用之前的操作方法,如果两个操作之间发生异常,则会造成数据不一致。

package lesson2;import java.sql.Connection;import java.sql.JDBCType;import java.sql.SQLException;public class AccountService {    private boolean flag;    public void setFlag(boolean flag) {        this.flag = flag;    }    AccountDao ad = new AccountDao();   //未来用别的模式初始化(工厂模式)     /**     * 增加账户的业务     * @param account     */    public void addAccount(Account account){        //如果有密码:需要加密 然后增加一条记录    }    /**     * 转账业务     * @param id1     * @param id2     * @param money     */    public void changeAccount(int id1,int id2,int money){        Connection con = null;        try {            con = JdbcUitl.getConn();            //开启事务,关闭自动提交            con.setAutoCommit(false);            Account account1 = ad.findById(id1);            Account account2 = ad.findById(id2);            int n1=ad.updateAccount(id1,account1.getMoney()-money);            if(flag)            throw new RuntimeException("可能出现某种异常");            int n2=ad.updateAccount(id2,account2.getMoney()+ money);            //提交事务            con.commit();        } catch (Exception e) {            e.printStackTrace();            try {                //回滚事务                con.rollback();            } catch (SQLException e1) {                // TODO Auto-generated catch block                e1.printStackTrace();            }        }finally{            //关闭事务            JdbcUitl.closeConnection();        }    }}

测试类

package lesson2;/** * 事物测试类 * @author hh * */public class JdbcDemo3 {    public static void main(String[] args) {        AccountService service = new AccountService();        service.setFlag(true);        service.changeAccount(1001, 1002, 100);    }}

代理模式

  • 代理模式(基于接口编程,业务要写成接口。所有操作,无论DAO还是业务都应该写成接口)。面向方面的编程aop。关心业务的人员只关心业务,关心事物的人员只关心事物。
    • 静态代理
      • 创建一个代理类,和被代理类实现用一个接口,并且把被代理类的实例作为自己的成员。
      • 静态代理本身也是一种架构模式
      • 缺陷:要做的辅助操作(实务,日志)在每个业务方法中都要进行重写。
    • 动态代理
      • 动态代理处理器 实现InvokeHandler接口
      • 把目标对象作为成员(要生成代理的对象)
      • 重写invoke方法:该方法会拦截所有的目标对象的方法
      • 产生代理对象,可以直接利用代理器处理器类,可单独写一个类;
      • 缺点:目标对象的所有方法都会被拦截处理。将来可以根据方法对象的属性判断是否需要加入事务操作。

静态代理

创建服务业务的接口

package lesson2.proxy;public interface UserService {    public void inertUser();    public void updateUser();    public void deleteUser();}

实际业务实现接口

package lesson2.proxy;public class UserServiceImpl implements UserService{    @Override    public void inertUser() {    //  System.out.println("开启事务");        System.out.println("通过一个or多个dao操作完成增加用户的业务");    //  System.out.println("提交事务,如果有异常就需要回滚事务");    }    @Override    public void updateUser() {    //  System.out.println("开启事务");        System.out.println("通过一个or多个dao操作完成修改用户的业务");    //  System.out.println("提交事务,如果有异常就需要回滚事务");    }    @Override    public void deleteUser() {        System.out.println("通过一个or多个dao操作完成删除用户的业务");    }}

代理实现接口

package lesson2.proxy;public class UserServiceProxy implements UserService{    private UserService userService;    public void setUserService(UserService userService) {        this.userService = userService;    }    @Override    public void inertUser() {        System.out.println("开启事务,日志,权限~~~~");        userService.inertUser();        System.out.println("提交事务,如果有异常就需要回滚事务");    }    @Override    public void updateUser() {        System.out.println("开启事务");        userService.updateUser();        System.out.println("提交事务,如果有异常就需要回滚事务");    }    @Override    public void deleteUser() {        System.out.println("开启事务");        userService.deleteUser();        System.out.println("提交事务,如果有异常就需要回滚事务");    }}

测试类

package lesson2.proxy;/** * 静态代理测试 * @author hh * */public class ProxyDemo1 {    public static void main(String[] args) {        UserServiceImpl us = new UserServiceImpl();        UserServiceProxy uproxy=new UserServiceProxy();         uproxy.setUserService(us);    //  us.updateUser();    //  us.inertUser();        uproxy.updateUser();        uproxy.inertUser();    }}

动态代理

可以发现静态代理中,要做的辅助操作(实务,日志)在每个业务方法中都要进行重写,繁琐。

代理处理器 代理工厂

package lesson2.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class ProxyFactoryBean implements InvocationHandler {    private Object target;// 目标对象 --->调用目标对象的任何方法都会被invoke方法拦截。    public ProxyFactoryBean(Object target) {        this.target = target;    }    /**     * 参数method 方法拦截后,拦截的目标对象的方法。 args 就是方法的参数。     */    @Override    public Object invoke(Object proxy, Method method, Object[] args)            throws Throwable {        //可以根据方法对象的特点来判断是否需要加入事务操作        System.out.println("开启事务 日志 权限等操纵");        method.invoke(target, args); // 目标方法的调用        System.out.println("提交事务,如果有异常就需要回滚事务");        return null;    }    /**     * 第一个参数:目标对象的类加载器     * 第二个参数:对象所实现的接口     * 第三个参数:代理处理器类     * @return     */    public Object getProxy() {        return Proxy.newProxyInstance(target.getClass().getClassLoader(),                target.getClass().getInterfaces(), this);    }}

测试类

package lesson2.proxy;/** * 动态代理测试 * @author hh * */public class ProxyDemo2 {    public static void main(String[] args) {        UserServiceImpl us = new UserServiceImpl(); //目标对象        //代理处理器、代理工厂        ProxyFactoryBean pfb= new ProxyFactoryBean(us);        //产生代理对象        UserService usProxy = (UserService)pfb.getProxy();        usProxy.deleteUser();        usProxy.updateUser();        usProxy.inertUser();    }}

用代理模式完成操作

  • 转账业务
  • 添加业务
  • 查询业务(不需要启动业务) 通过注解实现 是否需要事务 注解要加在接口上提炼事务的操作
  • 事务的提交回滚包装到专门的类中

创建业务接口

package lesson2.proxyaccount;import java.util.List;import lesson2.Account;public interface AccountService {    /**     * 增加账户     * @param account     * @return     */     public int addAccount(Account account);    /**     * 转账     * @param id1     * @param id2     * @param money     */    public void changeAccount(int id1,int id2,int money);    /**     * 查询所有     * @return     */    @Support    public List<Account> getAll();}

实际业务操作(实现接口方法)

package lesson2.proxyaccount;import java.util.List;import lesson2.Account;import lesson2.AccountDao;import lesson2.UserDao;public class AccountServiceImpl implements AccountService{    private AccountDao adDao = new AccountDao();    private boolean flag;    @Override    public int addAccount(Account account) {        int n =adDao.addAccount(account);        return n;    }    @Override    public void changeAccount(int id1, int id2, int money) {        Account account1 = adDao.findById(id1);        Account account2 = adDao.findById(id2);        //省略用户不存在或者账户余额不足的操作。        int n1=adDao.updateAccount(id1,account1.getMoney()-money);        if(flag){  //模拟出错            throw new RuntimeException("未知错误");        }        int n2=adDao.updateAccount(id2,account2.getMoney()+ money);    }    @Override    @Support    public List<Account> getAll() {        List<Account> accounts =adDao.getllAccount();        return accounts;    }}

动态代理操作(实现接口)

package lesson2.proxyaccount;import java.lang.reflect.InvocationHandler;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.sql.Connection;import java.sql.SQLException;import lesson2.JdbcUitl;public class ProxyFactoryBean implements InvocationHandler {    private Object target;    public ProxyFactoryBean(Object target) {        super();        this.target = target;    }    @Override    public Object invoke(Object proxy, Method method, Object[] arg) {        Support support = method.getAnnotation(Support.class);        if(support!=null&& support.value().equals("none")){            try {                proxy= method.invoke(target,arg);                System.out.println("没有事务");            } catch (Exception e) {                // TODO Auto-generated catch block                e.printStackTrace();            } finally{                JdbcUitl.closeConnection();            }            return proxy;        }        return proxyMerhod(proxy, method, arg);    }    private Object proxyMerhod(Object proxy, Method method, Object[] arg) {    //  Connection con = JdbcUitl.getConn();        try {            // 开始事务    //      con.setAutoCommit(false);            TransactionManager.begin();            proxy=method.invoke(target, arg); // 业务调用    //      con.commit(); // 提交事物            TransactionManager.commit();        } catch (Exception e) {            e.printStackTrace();            try {            //  con.rollback(); // 业务回滚                TransactionManager.rollback();            } catch (SQLException e1) {                e1.printStackTrace();            } finally {                JdbcUitl.closeConnection(); // 业务关闭            }        }        return proxy;    }    public Object getProxy() {        return Proxy.newProxyInstance(target.getClass().getClassLoader(),                target.getClass().getInterfaces(), this);    }}

事务处理(开始,提交,回滚)

package lesson2.proxyaccount;import java.sql.Connection;import java.sql.SQLException;import lesson2.JdbcUitl;public class TransactionManager {    public static void begin()throws SQLException{        Connection con =JdbcUitl.getConn();        con.setAutoCommit(false);    }    public static void commit()throws SQLException{        Connection con =JdbcUitl.getConn();        con.commit();    }    public static void rollback()throws SQLException{        Connection con =JdbcUitl.getConn();        con.rollback();    }}

用标签修饰方法

决定是否需要进行事务操作。例如查询所有就无需事务操作

package lesson2.proxyaccount;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface Support {    String value()default "none";}

标签要修饰在接口上

    /**     * 查询所有     * @return     */    @Support    public List<Account> getAll();

测试类

package lesson2.proxyaccount;import java.util.List;import lesson2.Account;public class AccountTest {    public static void main(String[] args) {        //未产生代理//      AccountServiceImpl accountService = new AccountServiceImpl();       //      accountService.changeAccount(1001, 1002, 100);        //产生代理        AccountServiceImpl accountService = new AccountServiceImpl();        ProxyFactoryBean pfb = new ProxyFactoryBean(accountService);        AccountService accountServiceProxy = (AccountService)pfb.getProxy();        //测试转账        accountServiceProxy.changeAccount(1001, 1002, 100);             //测试增加一条记录    //  Account account = new Account(1011, 100,"zhangsan2");       //  accountServiceProxy.addAccount(account);        //全部查询        List<Account> accounts = accountServiceProxy.getAll();        for (Account account : accounts) {            System.out.println(account);        }    }}

写在最后

这是jdbc学习的第二篇笔记。

1 0
原创粉丝点击