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

分页操作(排序)

与表相对应的用户类

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值