终于学完了数据库的连接,可以做一个完整的项目了,以前做的练习都没有关联到数据库,没法进行事务。

MVC框架

先上图:

老师画的图,有点乱,但是大概意思还是可以理解。

这个练习是简单的存储一个学生读了哪些书,存进数据库中,当然也可以查询。

主页图:

代码奉上:

index.jsp

  1. <span style="font-size:14px;"><%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
  2. <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
  3. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  4. <html>
  5. <head>
  6. <title>学生图书信息管理</title>
  7. </head>
  8. <body>
  9. <br><a href='<c:url value="/StudServlet?cmd=query"></c:url>' >学生图书信息查询</a>
  10. <br/><br/>
  11. <hr/>
  12. <form action='<c:url value="/StudServlet?cmd=save"></c:url>' method="post">
  13. 姓名<input type="text" name="name" /><br/><br/>
  14. <fieldset style="width: 200px">
  15. <legend>图书1</legend>
  16. 书名<input type="text" name="bookName" />
  17. 价格<input type="text" name="price" />
  18. </fieldset>
  19. <fieldset style="width: 200px">
  20. <legend>图书2</legend>
  21. 书名<input type="text" name="bookName" />
  22. 价格<input type="text" name="price" />
  23. </fieldset>
  24. <input type="submit" value="保存">
  25. </form>
  26. <br/>
  27. <a href='<c:url value="StudServlet?cmd=abc"></c:url>' >只是随便转转,不要开启事务</a>
  28. </body>
  29. </html>
  30. </span>

index请求的servlet.java

  1. <span style="font-size:14px;">package cn.hncu.stud.servlet;
  2. import java.io.IOException;
  3. import java.util.List;
  4. import java.util.Map;
  5. import javax.servlet.ServletException;
  6. import javax.servlet.http.HttpServlet;
  7. import javax.servlet.http.HttpServletRequest;
  8. import javax.servlet.http.HttpServletResponse;
  9. import cn.hncu.domain.Book;
  10. import cn.hncu.domain.Stud;
  11. import cn.hncu.stud.service.IStudService;
  12. import cn.hncu.stud.service.IStudServiceImpl;
  13. import cn.hncu.utils.TxProxy;
  14. public class StudServlet extends HttpServlet {
  15. //  IStudService service=new IStudServiceImpl();//这是直接在service层中开启事务,也是version 1
  16. //  IStudService service=TxProxy.getProxy(IStudServiceImpl.class);//version 2
  17. IStudService service=TxProxy.getProxy(new IStudServiceImpl());//version 3
  18. public void doGet(HttpServletRequest request, HttpServletResponse response)
  19. throws ServletException, IOException {
  20. doPost(request, response);
  21. }
  22. public void doPost(HttpServletRequest request, HttpServletResponse response)
  23. throws ServletException, IOException {
  24. request.setCharacterEncoding("utf-8");
  25. String cmd=request.getParameter("cmd");
  26. if("query".equals(cmd)){//不直接用cmd去判断,是为了防止cmd为null,更安全些
  27. query(request, response);
  28. }else if("save".equals(cmd)){
  29. save(request, response);
  30. }else if("abc".equals(cmd)){
  31. abc(request,response);
  32. }
  33. }
  34. private void query(HttpServletRequest request, HttpServletResponse response)
  35. throws ServletException, IOException {
  36. List<Map<String,String>> stud=service.query();
  37. request.setAttribute("stud", stud);
  38. request.getRequestDispatcher("/jsps/show.jsp").forward(request, response);
  39. }
  40. private void save(HttpServletRequest request, HttpServletResponse response)
  41. throws ServletException, IOException {
  42. //1.收集   2.组织
  43. String name=request.getParameter("name");
  44. //图书信息
  45. String[] bookNames=request.getParameterValues("bookName");
  46. String prices[]=request.getParameterValues("price");
  47. Stud stud=new Stud();
  48. stud.setName(name);
  49. if(bookNames==null||bookNames.length==0){//防护一下,防止为空,下面的price也应该做防护的,我省略了
  50. return;
  51. }
  52. for(int i=0;i<bookNames.length;i++){
  53. Book book=new Book();
  54. book.setName(bookNames[i]);
  55. book.setPrice(Double.parseDouble(prices[i]));
  56. //在这里完成两个值对象的“一对多”关系的数据封装
  57. stud.getBook().add(book);
  58. book.setStud(stud);
  59. }
  60. //3 调用service层
  61. try {
  62. service.save(stud);//把stud放进去就可以
  63. System.out.println("SUCCESSFULL");
  64. } catch (Exception e) {
  65. //导向失败页面
  66. }
  67. }
  68. private void abc(HttpServletRequest request, HttpServletResponse response)
  69. throws ServletException, IOException {
  70. service.abc();
  71. }
  72. }
  73. </span>

servlet要组织和封装从前台页面发来的数据,这里用了两个值对象:

Stud.java

  1. <span style="font-size:14px;">package cn.hncu.domain;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. /*
  5. * 一对多中“一方”值对象的建法
  6. */
  7. public class Stud {
  8. private String id;
  9. private String name;
  10. //为多方开一个集合,用来体现多表中“一对多”的关系
  11. private List<Book> books=new ArrayList<Book>();//注意:该集合要在类构造或之前就new出来
  12. public String getId() {
  13. return id;
  14. }
  15. public void setId(String id) {
  16. this.id = id;
  17. }
  18. public String getName() {
  19. return name;
  20. }
  21. public void setName(String name) {
  22. this.name = name;
  23. }
  24. public List<Book> getBook() {
  25. return books;
  26. }
  27. public void setBook(List<Book> book) {
  28. this.books = book;
  29. }
  30. @Override
  31. public String toString() {
  32. return "Stud [id=" + id + ", name=" + name + ", book=" + books + "]";
  33. }
  34. }
  35. </span>

Book.java

  1. <span style="font-size:14px;">package cn.hncu.domain;
  2. /*
  3. * 一对多中的“多”方值对象的建法
  4. */
  5. public class Book {
  6. private Integer id;//基本数据类型全用包装类来声明,为以后使用框架做技术准备----包装类能够兼容框架(因为一般框架都会使用类反射)
  7. private String name;
  8. private Double price;
  9. //专为“一”方添加一个对象类型的变量(不直接使用String studid)-----体现多表中的“一对多”关系
  10. private Stud stud=new Stud();//设置书的主人
  11. public Integer getId() {
  12. return id;
  13. }
  14. public void setId(Integer id) {
  15. this.id = id;
  16. }
  17. public String getName() {
  18. return name;
  19. }
  20. public void setName(String name) {
  21. this.name = name;
  22. }
  23. public Double getPrice() {
  24. return price;
  25. }
  26. public void setPrice(Double price) {
  27. this.price = price;
  28. }
  29. public Stud getStud() {
  30. return stud;
  31. }
  32. public void setStud(Stud stud) {
  33. this.stud = stud;
  34. }
  35. //多表关联时toString()有一个陷阱:不要出现一方输出另外一方,另外一方又输出这一方的情况,形成无穷循环
  36. @Override
  37. public String toString() {
  38. return "Book [id=" + id + ", name=" + name + ", price=" + price + "]";
  39. }
  40. }
  41. </span>

servlet调用service,service被动态代理的TxProxy.java

  1. <span style="font-size:14px;">package cn.hncu.utils;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. import java.sql.Connection;
  6. public class TxProxy implements InvocationHandler {
  7. private Object srcObj=null;
  8. private TxProxy(Object srcObj) {
  9. this.srcObj=srcObj;
  10. }
  11. /*version 1
  12. public static Object getProxy(Object srcObj){
  13. Object newObj=Proxy.newProxyInstance(
  14. TxProxy.class.getClassLoader(),
  15. srcObj.getClass().getInterfaces(),
  16. new TxProxy(srcObj));
  17. return newObj;
  18. }
  19. */
  20. /*version 2
  21. public static<T> T getProxy(Class<T> c){
  22. Object obj=null;
  23. try {
  24. obj = c.newInstance();
  25. } catch (Exception e) {
  26. throw new RuntimeException(c+"没有空参方法!");
  27. }
  28. Object newObj=Proxy.newProxyInstance(
  29. TxProxy.class.getClassLoader(),
  30. obj.getClass().getInterfaces(),
  31. new TxProxy(obj));
  32. return (T)newObj;
  33. }
  34. */
  35. public static<T> T getProxy(T srcObj){
  36. Object newObj=Proxy.newProxyInstance(
  37. TxProxy.class.getClassLoader(),
  38. srcObj.getClass().getInterfaces(),
  39. new TxProxy(srcObj));
  40. return (T)newObj;
  41. }
  42. /*version 1与version 2公用
  43. @Override
  44. public Object invoke(Object proxy, Method method, Object[] args)
  45. throws Throwable {
  46. Connection con=null;
  47. Object returnObj=null;
  48. try {
  49. con=ConnUtils5.getConn();
  50. con.setAutoCommit(false);
  51. System.out.println("开启事务.........");
  52. returnObj=method.invoke(srcObj, args);//放行
  53. con.commit();//
  54. System.out.println("提交事务.......");
  55. } catch (Exception e) {
  56. con.rollback();
  57. System.out.println("回滚事务.........");
  58. }finally{
  59. try {
  60. con.setAutoCommit(true);
  61. con.close();
  62. } catch (Exception e) {
  63. throw new RuntimeException(e.getMessage(), e);
  64. }
  65. }
  66. return returnObj;
  67. }
  68. */
  69. @Override
  70. public Object invoke(Object proxy, Method method, Object[] args)
  71. throws Throwable {
  72. if(method.isAnnotationPresent(Transaction.class)){
  73. System.out.println("此方法存在注解,进行拦截......");
  74. Connection con=null;
  75. Object returnObj=null;
  76. try {
  77. con=ConnUtils5.getConn();
  78. con.setAutoCommit(false);
  79. System.out.println("开启事务.........");
  80. returnObj=method.invoke(srcObj, args);//放行
  81. con.commit();//
  82. System.out.println("提交事务.......");
  83. } catch (Exception e) {
  84. con.rollback();
  85. System.out.println("回滚事务.........");
  86. }finally{
  87. try {
  88. con.setAutoCommit(true);
  89. con.close();
  90. } catch (Exception e) {
  91. throw new RuntimeException(e.getMessage(), e);
  92. }
  93. }
  94. return returnObj;
  95. }
  96. System.out.println("没有注解,直接放行....");
  97. return method.invoke(srcObj, args);
  98. }
  99. }
  100. </span>

service层的接口IStudService.java

  1. <span style="font-size:14px;">package cn.hncu.stud.service;
  2. import java.util.List;
  3. import java.util.Map;
  4. import cn.hncu.domain.Stud;
  5. import cn.hncu.utils.Transaction;
  6. public interface IStudService {
  7. public abstract List<Map<String,String>> query();
  8. @Transaction
  9. public abstract void save(Stud stud) throws Exception ;
  10. public abstract void abc();
  11. }
  12. </span>

接口用到的注解:

Transaction.java

  1. <span style="font-size:14px;">package cn.hncu.utils;
  2. import java.lang.annotation.ElementType;
  3. import java.lang.annotation.Retention;
  4. import java.lang.annotation.RetentionPolicy;
  5. import java.lang.annotation.Target;
  6. @Target(value=ElementType.METHOD)
  7. @Retention(RetentionPolicy.RUNTIME)
  8. public @interface Transaction {
  9. }
  10. </span>

实现类IStudServiceImpl.java

  1. <span style="font-size:14px;">package cn.hncu.stud.service;
  2. import java.sql.Connection;
  3. import java.sql.SQLException;
  4. import java.util.List;
  5. import java.util.Map;
  6. import cn.hncu.domain.Stud;
  7. import cn.hncu.stud.dao.BookDAO;
  8. import cn.hncu.stud.dao.BookJdbcDao;
  9. import cn.hncu.stud.dao.StudDAO;
  10. import cn.hncu.stud.dao.StudJdbcDao;
  11. import cn.hncu.utils.ConnUtils5;
  12. /*
  13. * 我们以后开发时通常要采用一个dao独立操作一个表,系统中有几个实体表就写几个dao,
  14. * 框架也是这么做的,架构好。
  15. *
  16. * 采用事务的场合:
  17. * 1.如果只有一个dao,但要执行多条sql语句且涉及增、删、改操作时要开启事务
  18. * 2.如果一个service调用多个dao,通常也要开启事务
  19. */
  20. public class IStudServiceImpl implements IStudService{
  21. public IStudServiceImpl() {
  22. }
  23. StudDAO stuDao=new StudJdbcDao();
  24. BookDAO booDao=new BookJdbcDao();
  25. @Override
  26. public List<Map<String, String>> query() {
  27. return stuDao.query();
  28. }
  29. /*
  30. * 事务要在service层做,dao层抛异常,在service抓异常,然后就行事务回滚,或者没有异常,提交
  31. * 但是,service拿到的要和dao拿到的是同一个Connection对象,否则无法进行提交或者回滚
  32. */
  33. @Override
  34. public void save(Stud stud) throws Exception {
  35. stuDao.save(stud);
  36. booDao.save(stud.getBook());
  37. }
  38. @Override
  39. public void abc() {
  40. System.out.println("什么都不做,只是来转转.....");
  41. }
  42. }
  43. </span>

service调用dao层,由于要一个表要对应一个dao,这里有stud表和book表,所以有两个dao

接口StudDAO.java

  1. <span style="font-size:14px;">package cn.hncu.stud.dao;
  2. import java.util.List;
  3. import java.util.Map;
  4. import cn.hncu.domain.Stud;
  5. public interface StudDAO {
  6. public abstract List<Map<String,String>> query();
  7. public abstract void save(Stud stud) throws Exception;
  8. }
  9. </span>

实现类StudJdbcDao.java

  1. <span style="font-size:14px;">package cn.hncu.stud.dao;
  2. import java.sql.Connection;
  3. import java.sql.PreparedStatement;
  4. import java.sql.ResultSet;
  5. import java.sql.SQLException;
  6. import java.util.ArrayList;
  7. import java.util.HashMap;
  8. import java.util.List;
  9. import java.util.Map;
  10. import java.util.UUID;
  11. import cn.hncu.domain.Stud;
  12. import cn.hncu.utils.ConnUtils5;
  13. public class StudJdbcDao implements StudDAO{
  14. @Override
  15. public List<Map<String, String>> query() {
  16. List<Map<String, String>> list=new ArrayList<Map<String,String>>();
  17. //一个map就是一行数据,List<Map<>>就是整个数据表
  18. Connection con=ConnUtils5.getConn();
  19. try {
  20. ResultSet rs=con.createStatement().executeQuery("select * from stud");
  21. while(rs.next()){
  22. Map<String, String> map=new HashMap<String, String>();
  23. map.put("id", rs.getString("id"));
  24. map.put("name", rs.getString("name"));
  25. list.add(map);
  26. }
  27. rs.close();
  28. } catch (SQLException e) {
  29. e.printStackTrace();
  30. }finally{
  31. try {
  32. con.close();
  33. } catch (SQLException e) {
  34. e.printStackTrace();
  35. }
  36. }
  37. return list;
  38. }
  39. @Override
  40. public void save(Stud stud) throws Exception {
  41. Connection con=ConnUtils5.getConn();
  42. String id=UUID.randomUUID().toString().replace("-", "");
  43. String sql="insert into stud(id,name) values(?,?)";
  44. PreparedStatement pst=con.prepareStatement(sql);
  45. pst.setString(1, id);
  46. pst.setString(2, stud.getName());
  47. pst.executeUpdate();
  48. //      int a=pst.executeUpdate();
  49. //System.out.println("影响 "+a+" 行");
  50. stud.setId(id);//为了“多方能够拿到一方的id,在这里补一方的id”
  51. }
  52. }
  53. </span>

接口BookDAO.java

  1. <span style="font-size:14px;">package cn.hncu.stud.dao;
  2. import java.util.List;
  3. import cn.hncu.domain.Book;
  4. public interface BookDAO {
  5. public abstract void save(List<Book> list) throws Exception;
  6. }
  7. </span>

实现类BookJdbcDao.java

  1. <span style="font-size:14px;">package cn.hncu.stud.dao;
  2. import java.sql.Connection;
  3. import java.sql.PreparedStatement;
  4. import java.sql.SQLException;
  5. import java.util.List;
  6. import cn.hncu.domain.Book;
  7. import cn.hncu.utils.ConnUtils5;
  8. public class BookJdbcDao implements BookDAO{
  9. @Override
  10. public void save(List<Book> list) throws Exception {
  11. Connection con=ConnUtils5.getConn();
  12. String sql="insert into book(name,price,studid) values(?,?,?)";
  13. //          INSERT INTO book(NAME,price,studid) VALUES("aa",33.5,"1");
  14. PreparedStatement pst=con.prepareStatement(sql);
  15. for(Book book:list){
  16. pst.setString(1, book.getName());
  17. pst.setDouble(2, book.getPrice());
  18. pst.setString(3, book.getStud().getId());
  19. pst.addBatch();//此处不要参数!!!!!添加到批处理(有很多条sql语句要执行时,用批处理)
  20. }
  21. pst.executeBatch();//执行批处理
  22. }
  23. }
  24. </span>

类和包:


效果图:

存储到数据库:

学生表:

图书表:

查询:

在项目中又有两个新的知识点:

ThreadLocal类:

java.lang.ThreadLocal<T>

这个类本质上就是里面维护着一个HashMap<Thread,Object>,key为线程,get方法就是通过Thread.currentThread()判断当前线程,然后在map中找到对应的Object,然后返回出去。

即:同一个线程拿同一个对象,不同线程则是不同对象。

这里做了一些练习:

ThreadLocalUtil.java

  1. <span style="font-size:14px;">package cn.hncu.threadLocDemo;
  2. import java.util.Random;
  3. public class ThreadLocalUtil {
  4. //  private static ThreadLocal<Object> t1=new ThreadLocal<Object>();//线程管理池Map<Thread,Object>
  5. private static MyThreadLocal<Object> t1=new MyThreadLocal<Object>();//线程管理池Map<Thread,Object>
  6. public static Object getObj(){
  7. Object obj=t1.get();//从池中拿一个obj
  8. if(obj==null){//如果池中没有
  9. Random r=new Random();
  10. obj=r.nextInt(500);
  11. t1.set(obj);//则new obj放进池中去
  12. }
  13. return obj;
  14. }
  15. }
  16. </span>

测试类Client.java

  1. <span style="font-size:14px;">package cn.hncu.threadLocDemo;
  2. import org.junit.Test;
  3. public class Client {
  4. @Test
  5. public void test1(){
  6. Object o1=ThreadLocalUtil.getObj();
  7. Object o2=ThreadLocalUtil.getObj();
  8. System.out.println("o1: "+o1+",o2: "+o2);
  9. System.out.println("o1==o2?  "+(o1==o2));
  10. }
  11. @Test
  12. public void test2(){
  13. test1();
  14. System.out.println();
  15. Object o3=ThreadLocalUtil.getObj();
  16. Object o4=ThreadLocalUtil.getObj();
  17. System.out.println("o3: "+o3+",o4: "+o4);
  18. System.out.println("o3==o4?  "+(o3==o4));
  19. System.out.println();
  20. new Thread(){
  21. @Override
  22. public void run() {
  23. Object o4=ThreadLocalUtil.getObj();
  24. Object o5=ThreadLocalUtil.getObj();
  25. System.out.println("o4: "+o4+",o5: "+o5);
  26. System.out.println("o4==o5?  "+(o4==o5));
  27. System.out.println();
  28. }
  29. }.start();
  30. }
  31. /*
  32. * 测试结果:obj1,obj2,obj3,obj4由于是同一个线程,所以obj也都相同,
  33. * obj5和obj6两者相同,但是他们是另外一个线程获取的,所以和obj1`obj4是不相等的
  34. */
  35. }
  36. </span>

测试图:

在知道ThreadLocal的功能后,我们自己模拟了一下它的功能:

MyThreadLocal.java

  1. <span style="font-size:14px;">package cn.hncu.threadLocDemo;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. /*
  5. * 自己模拟ThreadLocal功能,便于理解
  6. * 虽然表面的功能能够模拟出来,但是ThreadLocal真正的功能远远比这强,比如内存管理
  7. */
  8. public class MyThreadLocal<Object> {
  9. private Map<Thread, Object> map=new HashMap<Thread, Object>();
  10. public Object get(){
  11. Thread t=Thread.currentThread();
  12. return map.get(t);
  13. }
  14. public void set(Object obj){
  15. map.put(Thread.currentThread(), obj);
  16. }
  17. }
  18. </span>

同样可以得出一样的结果,但是仅仅只是模拟了表面功能!

动态代理模板

前面已经贴出代码,但是这里用到了类反射、注解、泛型和动态代理,这几个知识点不是很熟,所以在这里再写遍,提醒一下自己!

TxProxy.java

    1. <span style="font-size:14px;">package cn.hncu.utils;
    2. import java.lang.reflect.InvocationHandler;
    3. import java.lang.reflect.Method;
    4. import java.lang.reflect.Proxy;
    5. import java.sql.Connection;
    6. public class TxProxy implements InvocationHandler {
    7. private Object srcObj=null;
    8. private TxProxy(Object srcObj) {
    9. this.srcObj=srcObj;
    10. }
    11. public static<T> T getProxy(T srcObj){
    12. Object newObj=Proxy.newProxyInstance(
    13. TxProxy.class.getClassLoader(),
    14. srcObj.getClass().getInterfaces(),
    15. new TxProxy(srcObj));
    16. return (T)newObj;
    17. }
    18. @Override
    19. public Object invoke(Object proxy, Method method, Object[] args)
    20. throws Throwable {
    21. if(method.isAnnotationPresent(Transaction.class)){
    22. System.out.println("此方法存在注解,进行拦截......");
    23. Connection con=null;
    24. Object returnObj=null;
    25. try {
    26. con=ConnUtils5.getConn();
    27. con.setAutoCommit(false);
    28. System.out.println("开启事务.........");
    29. returnObj=method.invoke(srcObj, args);//放行
    30. con.commit();//
    31. System.out.println("提交事务.......");
    32. } catch (Exception e) {
    33. con.rollback();
    34. System.out.println("回滚事务.........");
    35. }finally{
    36. try {
    37. con.setAutoCommit(true);
    38. con.close();
    39. } catch (Exception e) {
    40. throw new RuntimeException(e.getMessage(), e);
    41. }
    42. }
    43. return returnObj;
    44. }
    45. System.out.println("没有注解,直接放行....");
    46. return method.invoke(srcObj, args);
    47. }
    48. }
    49. </span>

最新文章

  1. 实际项目中的一个angularjs 应用
  2. 代理委托和block
  3. [转]如何判断js中的数据类型
  4. 最近面试遇到的Windows相关的题目
  5. Excel导出问题(导出时不去掉前面的0)(转)
  6. ORACLE CASE函数 .
  7. Netty4.0学习教程
  8. Learning To Rank之LambdaMART前世今生
  9. (三目运算符)PHP中问号?和冒号: 的作用
  10. [jdoj1817]Drainage Ditches_网络流
  11. OO第三次博客作业
  12. SQL中NVL函数
  13. SQL Server 存储过程的运用
  14. Python+Appium学习篇之WebView处理
  15. CPU指令分类
  16. 怎样使用EOS.JS的API
  17. linux rpm yum 安装 软件
  18. kali安全工具
  19. unity, ios skin crash
  20. javashop组件开发指南

热门文章

  1. mysql函数总结
  2. DFS:POJ1562-Oil Deposits(求连通块个数)
  3. JAVA复制
  4. RHEL6.5上升级OpenSSH7.4p1
  5. ubuntu介绍以及使用
  6. 开始 python programming第三版案例分析
  7. IS-IS IGP
  8. CodeForces 321C Ciel the Commander
  9. Leetcode 368.最大整除子集
  10. 【转】OPC远程访问相关配置信息