精华内容
下载资源
问答
  • servlet中如何开始事务
    千次阅读
    2021-03-10 13:47:48

    DAO模式

    什么是dao模式?

    DAO(Data Access Object)顾名思义是一个为数据库或其他持久化机制提供了抽象接口的对象,在不暴露底层持久化方案实现细节的前提下提供了各种数据访问操作。在实际的开发中,应该将所有对数据源的访问操作进行抽象化后封装在一个公共API中。用程序设计语言来说,就是建立一个接口,接口中定义了此应用程序中将会用到的所有事务方法。在这个应用程序中,当需要和数据源进行交互的时候则使用这个接口,并且编写一个单独的类来实现这个接口,在逻辑上该类对应一个特定的数据存储。DAO模式实际上包含了两个模式,一是Data Accessor(数据访问器),二是Data Object(数据对象),前者要解决如何访问数据的问题,而后者要解决的是如何用对象封装数据。

    信息系统的开发架构

    客户层-------显示层-------业务层---------数据层---------数据库

    1.客户层:客户层就是客户端,简单的来说就是浏览器。
    2.显示层:JSP/Servlet,用于给浏览器显示。
    3.业务层:对于数据层的原子操作进行整合。
    4.数据层:对于数据库进行的原子操作,增加、删除等;

    DAO(Data Access Object)介绍

    DAO应用在数据层那块(对于数据库进行的原子操作,增加、删除等;),用于访问数据库,对数据库进行操作的类。

    DAO设计模式的结构

    DAO设计模式一般分为几个类:

    1.VO(Value Object):一个用于存放网页的一行数据即一条记录的类,比如网页要显示一个用户的信息,则这个类就是用户的类。
    2.DatabaseConnection:用于打开和关闭数据库。
    3.DAO接口:用于声明对于数据库的操作。
    4.DAOImpl:必须实现DAO接口,真实实现DAO接口的函数,但是不包括数据库的打开和关闭。
    5.DAOProxy:也是实现DAO接口,但是只需要借助DAOImpl即可,但是包括数据库的打开和关闭。
    6.DAOFactory:工厂类,含有getInstance()创建一个Proxy类。

    DAO的好处

    DAO的好处就是提供给用户的接口只有DAO的接口,所以如果用户想添加数据,只需要调用create函数即可,不需要数据库的操作。

    Properties类(配置文件)

    Java中的配置文件常为properties文件,格式为文本文件,文件的内容是“键=值”格式,注信息使用#注释。

    步骤:

    1.添加.properties文件

    new ——》 File命令 新建properties文件

    2.添加文件内容

    例:连接数据库参数

    driver=com.mysql.jdbc.Driver
    
    url=jdbc:mysql://localhost:3306/pets
    
    user=pets
    
    password=111111
    

    3.读取配置文件

    properties类的常用方法

    String getProperty(String key);根据指定的键返回一个字符串值。
    
    Object setProperty(String key,String value);调用基类的方法来添加键值对;
    
    void load(InputStream in);从输入流中读取属性列表,通过对指定文件进行装载获取该文件中的所有键值对;
    
    void clear();清除所装载的键值对.
    
    示例:
    
    //创建对象
    
       Properties para = new Properties();
    
    //创建输入流
    
       InputStream inputStream =
    
    databaseUtil.class.getClassLoader().getResourceAsStream(str);
    
    //从输入流中读取属性列表
    
       try {
    
          para.load(inputStream);
    
          String dri = para.getProperty("driver");
    
          String url = para.getProperty("url");
    
          String user = para.getProperty("user");
    
          String password = para.getProperty("password");
    
          inputStream.close();
    
       } catch (IOException e) {
    
          e.printStackTrace();
    
       }
    

    Servlet

    概述

    Servlet是sun公司提供的一门用于开发动态web资源的技术。
      Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:
      1、编写一个Java类,实现servlet接口。
      2、把开发好的Java类部署到web服务器中。
      按照一种约定俗成的称呼习惯,通常我们也把实现了servlet接口的java程序,称之为Servlet

    Servlet接口实现类

    • Servlet接口SUN公司定义了两个默认实现类,分别为:GenericServlet、HttpServlet。
    • HttpServlet指能够处理HTTP请求的servlet,它在原有Servlet接口上添加了一些与HTTP协议处理方法,它比Servlet接口的功能更为强大。因此开发人员在编写Servlet时,通常应继承这个类,而避免直接去实现Servlet接口。
    • HttpServlet在实现Servlet接口时,覆写了service方法,该方法体内的代码会自动判断用户的请求方式。
      如为GET请求,则调用HttpServlet的doGet方法
      如为Post请求,则调用doPost方法

    配置Servlet

    <servlet>
    		<!--给servlet取得的名字,一般与servlet类名相同-->
            <servlet-name>userServerlet</servlet-name>
            <!--servlet全限定类名,也就是servlet的位置-->
           <servlet-class>cn.kgc.kb11.serverlet.UserServerlet</servlet-class>
        </servlet>
    
        <servlet-mapping>
        	<!--与上面的servlet名字相同-->
            <servlet-name>userServerlet</servlet-name>
            <!--浏览器通过该url找到servlet,"/"一定要加-->
            <url-pattern>/doCreate</url-pattern>
        </servlet-mapping>
    

    示例

    package cn.kgc.kb11.serverlet;
    
    import cn.kgc.kb11.service.UserService;
    import cn.kgc.kb11.service.impl.UserServiceImpl;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * @Author ZhangPeng
     * @Date 2021/3/9
     * @Description
     */
    public class UserServerlet extends HttpServlet {
        UserService user = new UserServiceImpl();
    
        public void create(HttpServletRequest req, HttpServletResponse resp) throws IOException{
            //注册
            String name = req.getParameter("user");
            String pwd = req.getParameter("pwd");
            String cfmPwd = req.getParameter("cfmPwd");
            boolean isSuccess = user.register(name, pwd, cfmPwd);
            //System.out.println(isSuccess ? "注册成功" : "注册失败");
    
            if (isSuccess) {
                resp.sendRedirect("/login/home.jsp");
            } else {
                //req.getRequestDispatcher("/login/createUser.jsp").forward(req,resp);
                resp.sendRedirect("/login/createUser.jsp");
            }
        }
    
        public void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
    
            //登录
            String name = req.getParameter("user");
            String pwd = req.getParameter("pwd");
            boolean isSuccess = user.login(name,pwd);
            if (isSuccess){
                req.getRequestDispatcher("/login/doLogin.jsp").forward(req,resp);
            }else {
                resp.sendRedirect("/login/home.jsp");
            }
        }
    
        public void modify(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
            //修改密码
            String name = req.getParameter("user");
            String oldPwd = req.getParameter("oldPwd");
            String newPwd = req.getParameter("newPwd");
            boolean isSuccess = user.modify(name,oldPwd,newPwd);
            if (isSuccess){
                req.getSession().setAttribute("isSuccess",true);
                req.getRequestDispatcher("/login/doModify.jsp").forward(req,resp);
            }else {
                req.getSession().setAttribute("isSuccess",false);
                req.getRequestDispatcher("/login/doModify.jsp").forward(req,resp);
            }
        }
    
        public void delete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
            //删除用户
            String name = req.getParameter("user");
            String pwd = req.getParameter("pwd");
            boolean isSuccess = user.delete(name,pwd);
            if (isSuccess){
                req.getSession().setAttribute("isSuccess",true);
                req.getRequestDispatcher("/login/doDelete.jsp").forward(req,resp);
            }else {
                req.getSession().setAttribute("isSuccess",false);
                req.getRequestDispatcher("/login/doDelete.jsp").forward(req,resp);
            }
        }
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String type = req.getParameter("type");
            if ("login".equals(type)){
                login(req,resp);
            }else if ("create".equals(type)){
                create(req,resp);
            }else if ("modify".equals(type)){
                modify(req,resp);
            }else {
                delete(req,resp);
            }
    
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
        }
    
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            super.service(req, resp);
        }
    }
    
    
    更多相关内容
  • Jsp-Servlet-JavaBean企业事务管理系统 类似于新闻发布系统 本资源是课堂老师分享的资源
  • 事务出现错误 " ) ; } finally { System. out .println( " 关闭资源 " ) ; } return invoke ; } }) ; return userService1 ; } } 配置文件: 示例 接口名与实现类的包名+类名

    这是一个简单的模型。

    public class ProxyServiceImpl{
        //加载配置文件
        private static Map<String,String> map = new HashMap<>();
        static{
            //使用util下的ResourceBundle加载properties配置文件
            ResourceBundle resourceBundle = ResourceBundle.getBundle("peizhi");
            Enumeration<String> keys = resourceBundle.getKeys();
            while(keys.hasMoreElements()){
                String key = keys.nextElement();
                String value = resourceBundle.getString(key);
                map.put(key,value);
            }
        }
    
        public <T> T getService(Class<T> clazz) {
            if(!clazz.isInterface()){
                throw new RuntimeException("不是一个接口");
            }
            String className = clazz.getSimpleName();
            if(!map.containsKey(className)){
               throw new RuntimeException("未知的接口");
            }
            String string = map.get(className);
            Class<?> aClass = null;
            try {
                aClass = Class.forName(string);
            } catch (Exception e) {
                e.printStackTrace();
            }
            final Class<?> finalAClass = aClass;
            T userService1 = (T)Proxy.newProxyInstance(aClass.getClassLoader(), new Class[]{clazz}, new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    Object invoke = null;
                    try {
                        System.out.println("开启事务");
    
                        invoke = method.invoke(finalAClass.newInstance(), args);
                        System.out.println("事务提交");
                    } catch (Exception e) {
                        e.printStackTrace();
                        System.out.println("事务回滚");
                        throw new RuntimeException("事务出现错误");
                    } finally {
                        System.out.println("关闭资源");
                    }
                    return invoke;
                }
            });
            return userService1;
        }
    }

    配置文件:

    示例

    接口名与实现类的包名+类名

    展开全文
  • 采用servlet+mysql+jdbc实现后台注册登录上传头像等
  • 2.servlet实现登录功能

    千次阅读 2022-03-02 17:41:18
    在该案例,通过servlet实现了用户登录的功能。主要涉及前端页面请求数据,servlet程序处理请求,业务逻辑层调用相关的dao层,在数据库提取数据并return给service层进行验证,将验证结果经过servlet返还给前端页面...

    在该案例中,通过servlet实现了用户登录的功能。主要涉及前端页面请求数据,servlet程序处理请求,业务逻辑层调用相关的dao层,在数据库提取数据并return给service层进行验证,将验证结果经过servlet返还给前端页面,进行显示。

    相关代码

    创建admin数据表

    CREATE TABLE `admin` (
      `username` VARCHAR(20) NOT NULL,
      `password` VARCHAR(20) NOT NULL,
      `phone` VARCHAR(11) NOT NULL,
      `Address` VARCHAR(20) NOT NULL,
      PRIMARY KEY (`username`)
    ) ENGINE=INNODB DEFAULT CHARSET=utf8mb3
    

    创建前端页面

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登录页面</title>
    </head>
    <body>
        <form action="/servlet_war_exploded/login" method="post">
            用户名:<input type="text" name="username"><br/>
            密码:<input type="password" name="password"><br/>
            <input type="submit" value="登录">
        </form>
    </body>
    </html>
    

    创建Admin.java实体类

    package com.ws.servletProject.entity;
    
    public class Admin {
        private String username;
        private String password;
        private String phone;
        private String Address;
    
        public Admin() {
        }
    
        public Admin(String username, String password, String phone, String address) {
            this.username = username;
            this.password = password;
            this.phone = phone;
            Address = address;
        }
    
        @Override
        public String toString() {
            return "Admin{" +
                    "username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    ", phone='" + phone + '\'' +
                    ", Address='" + Address + '\'' +
                    '}';
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public String getPhone() {
            return phone;
        }
    
        public void setPhone(String phone) {
            this.phone = phone;
        }
    
        public String getAddress() {
            return Address;
        }
    
        public void setAddress(String address) {
            Address = address;
        }
    }
    
    

    创建配置文件database.properties

    通过该文件提供数据库的一些信息的配置,然后会通过DbUtils.java程序来加载该文件,连接数据库

    #key=value
    driverClassName=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/practice?useUnicode=true&characterEncoding=utf-8&userSSL=false&serverTimezone=GMT%2B8
    #url=jdbc:mysql://localhost:3306/girls
    username=root
    password=123
    #initial connection Size
    initialSize=10
    #min idle connecton size
    minIdle=5
    #max active connection size
    maxActive=20
    #max wait time (5000 mil seconds)
    maxWait=5000
    

    创建工具类DbUtils.java

    该程序主要通过创建数据库连接池(德鲁伊连接池),提供连接,事务控制以及释放连接资源

    package com.ws.servletProject.utils;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import com.alibaba.druid.pool.DruidDataSourceFactory;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.Properties;
    @SuppressWarnings({"all"})
    public class DbUtils {
        //创建连接池
        private static DruidDataSource ds;
        private static final ThreadLocal<Connection> THREAD_LOCAL = new ThreadLocal<>();//控制连接的线程
    
        //静态代码块,初始配置内容
        static {
            Properties properties = new Properties();
            InputStream inputStream = DbUtils.class.getResourceAsStream("/database.properties");//获取一个字节输入流
            try {
                properties.load(inputStream);
                //创建连接池
                ds = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    
        //获得连接
        public static Connection getConnection(){
            Connection connection = THREAD_LOCAL.get();//获取连接
            try {
                if (connection == null){
                    connection = ds.getConnection();//在连接池中拿取一个connection
                    THREAD_LOCAL.set(connection);
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return connection;
        }
        //事务控制
        //开启事务
        public static void begin(){
            Connection connection = null;
            try {
                connection = getConnection();
                connection.setAutoCommit(false);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        //提交事务
        public static void commit(){
            Connection connection = null;
            try {
                connection = getConnection();
                connection.commit();
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                closeAll(connection,null,null);//提交事务时候释放连接,connection,statement,resoultset
            }
        }
        //事务回滚
        public static void rollback(){
            Connection connection = null;
            try {
                connection = getConnection();
                connection.rollback();
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                closeAll(connection,null,null);//提交事务时候释放连接,connection,statement,resultset
            }
        }
    
        //释放资源
        public static void closeAll(Connection connection, Statement statement, ResultSet resultSet){
            try {
                if (resultSet != null){
                    resultSet.close();
                }
                if (statement != null){
                    statement.close();
                }
                if (connection != null){
                    connection.close();
                    THREAD_LOCAL.remove();//将连接从线程对象中移除
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    
    

    创建DAO层相关代码

    创建AdminDao.java接口

    该接口规定操作数据库的一些方法

    package com.ws.servletProject.dao;
    
    import com.ws.servletProject.entity.Admin;
    
    import java.util.List;
    
    public interface AdminDao {
        public int insert(Admin admin);
        public int delete(String username);
        public int update(Admin admin);
    
        public Admin select(String username);
        public List<Admin> selectAll();
    }
    
    

    创建AdminDaoImpl.java实现接口类

    通过该程序可以对数据库实现具体的SQL语句操作,实质上也算是工具类

    package com.ws.servletProject.dao.impl;
    
    import com.ws.servletProject.dao.AdminDao;
    import com.ws.servletProject.entity.Admin;
    import com.ws.servletProject.utils.DbUtils;
    import org.apache.commons.dbutils.QueryRunner;
    import org.apache.commons.dbutils.handlers.BeanHandler;
    import org.apache.commons.dbutils.handlers.BeanListHandler;
    
    import java.sql.SQLException;
    import java.util.List;
    
    public class AdminDaoImpl implements AdminDao {
        private QueryRunner queryRunner = new QueryRunner();
        @Override
        public int insert(Admin admin) {
            return 0;
        }
    
        @Override
        public int delete(String username) {
            return 0;
        }
    
        @Override
        public int update(Admin admin) {
            return 0;
        }
    
        @Override
        public Admin select(String username) {
            try {
                Admin admin = queryRunner.query(DbUtils.getConnection(),"select * from admin where username=?;",new BeanHandler<Admin>(Admin.class),username);
                return admin;
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        @Override
        public List<Admin> selectAll() {
            try {
                List<Admin> query = queryRunner.query(DbUtils.getConnection(), "select * from admin;", new BeanListHandler<Admin>(Admin.class));
                return query;
            } catch (SQLException e) {
                e.printStackTrace();
            }
    
            return null;
        }
    }
    
    

    创建业务逻辑层相关代码(service)

    创建AdminService.java接口

    该程序主要是用来规定一些业务逻辑的方法

    package com.ws.servletProject.service;
    
    import com.ws.servletProject.entity.Admin;
    
    import java.util.List;
    
    public interface AdminService {
        public Admin login(String username, String password);//通过servlet传入的 username,password 调用AdminDao对象进行数据提取,并且验证
        public List<Admin> showAllAdmin();//展示所有用户的方法
    }
    
    

    创建AdminServiceImpl.java实现类

    package com.ws.servletProject.service.impl;
    
    import com.ws.servletProject.dao.AdminDao;
    import com.ws.servletProject.dao.impl.AdminDaoImpl;
    import com.ws.servletProject.entity.Admin;
    import com.ws.servletProject.service.AdminService;
    import com.ws.servletProject.utils.DbUtils;
    
    import java.util.List;
    
    public class AdminServiceImpl implements AdminService {
        private AdminDao adminDao = new AdminDaoImpl();
        @Override
        public Admin login(String username, String password) {
            Admin result = null;//创建一个Admin类,用来返回数据
            try {
                DbUtils.begin();//开启事务
                Admin admin = adminDao.select(username);//执行查询
                if (admin != null){//进行判断
                    if (admin.getPassword().equals(password)){
                        result = admin;//赋值
                    }
                }
                DbUtils.commit();//提交事务
            } catch (Exception e) {
                DbUtils.rollback();//如果出现异常,进行事务的回滚
                e.printStackTrace();
            }
            return result;
        }
    
        @Override
        public List<Admin> showAllAdmin() {
            List<Admin> admins = null;
            try {
                DbUtils.begin();
                admins = adminDao.selectAll();
                DbUtils.commit();
            } catch (Exception e) {
                DbUtils.rollback();
                e.printStackTrace();
            }
            return admins;
        }
    }
    
    

    创建LoginServlet.java

    package com.ws.servletProject.servlet;
    
    import com.ws.servletProject.entity.Admin;
    import com.ws.servletProject.service.AdminService;
    import com.ws.servletProject.service.impl.AdminServiceImpl;
    import com.ws.servlet_.HttpsServlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    @WebServlet(value = "/login")
    public class LoginServlet extends HttpsServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            req.setCharacterEncoding("UTF-8");
            resp.setContentType("text/html;charset=UTF-8");
            //接收参数
            String username = req.getParameter("username");
            String password = req.getParameter("password");
            //调用业务逻辑进行验证
            AdminService adminService = new AdminServiceImpl();
            Admin admin = adminService.login(username, password);
            //验证用户是否存在之后,对返回的结果进行处理
            //响应给客户端一个结果
            PrintWriter writer = resp.getWriter();
            if (admin != null){
                writer.println("<html>");
                writer.println("<head>");
                writer.println("<meta charset='UTF-8'>");
                writer.println("<title>结果</title>");
                writer.println("</head>");
                writer.println("<body>");
                writer.println("<h1>登录成功!</h1>");
                writer.println("</body>");
                writer.println("</html>");
            }else {
                writer.println("<html>");
                writer.println("<head>");
                writer.println("<meta charset='UTF-8'>");
                writer.println("<title>结果</title>");
                writer.println("</head>");
                writer.println("<body>");
                writer.println("<h1>登录失败!</h1>");
                writer.println("</body>");
                writer.println("</html>");
            }
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
    
    展开全文
  • IoC思想、DI依赖注入、Bean的实例方式、Bean种类、Bean作用域范围、Bean生命周期管理、依赖注入、注解装配Bean、整合Junit测试、WEB开发集成spring、AOP...JdbcTemplate模板使用、C3P0数据源配置、声明式事务管理、注解事务管理...
  • 用 JOTM 向Servlet中添加事务

    千次阅读 2008-07-05 19:20:00
    J2EE 除了提供了 servlet 之外,还提供了大量的其它功能。Servlet 开发者们也许难得使用这些功能,不情愿也没有时间用一个超出所需的大型 J2EE 服务器来替换自己的简单的 servlet。然而,依据J2EE 的模块化特征,有...
    J2EE 除了提供了 servlet 之外,还提供了大量的其它功能。Servlet 开发者们也许难得使用这些功能,不情愿也没有时间用一个超出所需的大型 J2EE 服务器来替换自己的简单的 servlet。然而,依据J2EE 的模块化特征,有可能将负责特定 J2EE 功能的小组件整合到 servlet 容器里,以此来增强 WEB 应用程序。其中之一就是事务。有关 J2EE 事务的完整描述,您可以参考 Onjava上的其他 三篇文章,现在只需知道事务是资源的操作步骤(例如:数据库),它由四个属性定义,这四个属性根据其首字母浓缩为 ACID:

      原子性:事务的操作,或者是全部成功(此时提交事务),或者是全部不成功(此时回滚事务),谓之为 all-or-nothing 属性。一个事务应该被视为单个工作单元,在一个事务里面绝对不可能同时存在完成了的和没有完成的操作。

      一致性:完成了的事务将资源从一个有效状态转变为另一个有效状态。一致性的具体例子有:数据库的参照完整性和表中的主键唯一性。

      独立性在事务没有提交之前,事务作用的共享资源的改变在事务之外是不可见的。独立性确保了不同事务不会同时访问正在更新的数据。

      持久性:由事务提交的改变会永久存在。

      JOTM (Java Open Transaction Manager)是由ObjectWeb协会开发的功能完整的且资源开放的独立的事务管理器。它提供了 JAVA 应用程序的事务支持,而且与 JTA( JAVA 事务 API)兼容。您可以在JOTM home page了解到更多的详细信息。在 TOMCAT(或其它 Servlet 容器)整合了 JOTM 后,JSP 和 servlet 的开发者们就可以获得事务的优势轻而易举的创建更多健壮的 web 应用程序。

      为了突出事务是怎样增强 web 应用程序的,举一个常用的例子, web 浏览器与客户端交互的 ATM 。

      ATM 样例:

      情景

      此例比较简单:一个客户想从 ATM 提款,输入了他的客户名称,john_doe;想提款数,$50。如果他的银行帐户上有足够的钱并且在 ATM 机上有足够的现金的话,应用程序就能给他相当数目的现金,并从银行帐户上提出同样的数目。否则,操作中断,并且除出现错误信息之外,其他都不会改变。我们无需担心安全问题,只是在猜想用户是否正确授权。

      这是一个非常简单的例子,但是如果不使用事务,用别的方法执行起来将会很难。客户端操作将会涉及到两个不同的资源:ATM 和客户银行帐号。它们会自动的在应用程序设计中产生 ACID 问题。例如:如果在 ATM 上操作成功而在银行帐户上却失败(也许是因为交流失败),客户将会取到钱,但是他的帐户将不会更新。对于银行来说,这就亏大了。更糟的是,如果银行帐户更新了,但是由于一个错误阻止 ATM 传送钱,客户得不到现金,但是帐户上却提掉了这笔款。

      为了防止出现上述事故,在你的应用程序里,你能够 1) 联系两个资源,并告知两者客户执行的所有当前操作,2) 询问两者是否能执行操作,3)如果两者都同意,则请求操作。即使这样,此方法也不能谓之足够健壮,因为,如果客户帐户上的钱在第二步和第三步的时候被另外一操作提走,提款可能会失败,例如,客户帐户不能出现逆差。

      事务能使应用程序更简单更健壮的之处就是:在同一事务的两个资源上执行所有的操作的时候,它将会解决 ACID 的问题(尤其是原子性)。

      应用程序设计

      数据层:在数据层,有两个不同的数据库,并各自有一张表。为了使例子更接近实际,我们使用两个不同的数据库,因为有可能从 ATM 提走不是属于该客户帐户的款(请参见下文配置数据库)。

      banktest 包含代表客户帐号的 account 表。

      atmtest包含代表 ATM 的 atm 表。

      逻辑层:在逻辑层,有三个类来访问资源和执行操作:

      foo.BankAccount 代表给定客户的银行帐号 account,并能通过 JDBC在 account 执行数据库操作。

      bar.ATM 代表 ATM,并在 atm 表上执行 JDBC 操作。

      bar.CashDelivery 使用前面两个类来执行一个客户操作。

      所有逻辑在 CashDelivery.java 的 deliverCash 方法中实现。

      javax.transaction.UserTransaction 接口用于划分事务所有 utx.begin() 和 utx.commit() (或 utx.rollback())之间的操作在同一事务内执行。这确保了应用程序不会受到如前述的遭遇。

      事务使得应用程序更为简单,由以下简单的步骤组成:

      1. 开始事务。

      2. 联系客户的银行帐户并从帐户上提款。

      3. 告诉 ATM 传送钱。

      4. 完成事务:如果所有事件完成,提交事务。否则,回滚事务。

      5. 报告客户事务结果。如果事务成功,现金将被提出,钱数也将从帐户上提出。否则,一切都不会改变。

    例1. CashDelivery.java

         public boolean deliver(String client, int value) {
    InitialContext ctx          = new InitialContext();
    UserTransaction utx = (UserTransaction)
    ctx.lookup("java:comp/UserTransaction");
        ...
    boolean success = false;
    try {
    // 开始事务
    utx.begin();
    
    //联系客户银行帐户...
    BankAccount account = new BankAccount(client);
    
    // ... 从帐户上提款
    account.withdraw(value);
    
    //联系 ATM...
    ATM atm = new ATM();
    
    // ... 传送现金给客户
    atm.deliverCash(value);
    
    //一切正常
    success = true;
    
    } catch (Exception e) {
    // 出现故障,不得不
    // 报告给客户
    explanation += e.getMessage();
    
    } finally {
    try {
    if (success) {
    /*一切正常提交事务
    直到现在,钱才真正的从帐户上提出,并且将现金传送给客户。
                    */
    utx.commit();
    
    } else {
    /* 出现故障,就回滚事务。
    *所有在事务内处理的操作不会发生。
                    */
    utx.rollback();
                }
    } catch (Exception e) {
    /* 在完成事务的过程中出现故障,
    *仍旧保证
    * 事务内的操作不会发生。/
                */
    // 报告给客户
    explanation += "/n" + e.getMessage();
    
    //最后,事务不会成功
    success = false;
    
    } finally {
    return success;
            }
        }
    }

      表示层:在表示层,就用程序由两个 JSP 文件组成:

      atm.jsp, 应用程序,它发送给bar.CashDelivery 类客户登录和提款数目,并显示客户操作的结果 。

      admin.jsp,,用于显示和更新两个资源的信息。(它不属于应用程序设计的部分,但是添加它来简化资源更新,比如处理客户帐户的钱数。)

     

    图1 应用程序设计

      配置数据库

      关于数据库,建议使用MySQL 4.0.12和相应的 JDBC 驱动程序(见Resources)。默认情况下,MySQL 表不会受影响。为支持事务,表在创建的时候设置为 InnoDB 类型。另外,为启用 InnoDB 类型,您可以将 MySQL 配置文件内的 #skip-innodb 行注释掉。

      已配置了一个 MySQL 的例子,用户名为 javauser,密码为 javadude。确保该用户已被创建并且拥有创建数据库的权限。

      创建数据库和表的脚本在 scripts/ 目录下的 example file 内含有。它将创建一个 account 表并插入两个客户:john_doe 他的帐户金额为 $100。jane_doe 他的帐户金额为 $600。

    例2 创建 account 表

          mysql> CREATE DATABASE banktest;
    mysql> USE banktest;
    mysql> CREATE TABLE account(
    -> client VARCHAR(25) NOT NULL PRIMARY KEY,
    -> money INT) TYPE=InnoDB;
    mysql> INSERT INTO account valueS("john_doe", 100);
    mysql> INSERT INTO account valueS("jane_doe", 600);
    mysql> SELECT * FROM account;
    +----------+-------+
    | client   | money |
    +----------+-------+
    | john_doe |   100 |
    | jane_doe |   600 |
    +----------+-------+

    脚本还会创建有 $500 可用现金的 atm 表。

    例3 创建 atm 表

          mysql> CREATE DATABASE atmtest;
    mysql> USE atmtest;
    mysql> CREATE TABLE atm(
    -> id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    -> cash INT) TYPE=InnoDB;
    mysql> INSERT INTO atm valueS(null, 500);
    mysql> SELECT * FROM atm;
    +----+------+
    | id | cash |
    +----+------+
    |  1 |  500 |
    +----+------+

      最后,复制 $CATALINA_HOME/shared/lib 内的 JDBC 驱动程序 .jar 文件。

      获取并安装 TOMCAT:本章主要介绍 Tomcat 4.1.18 及以上的版本。首先确保没有使用以前的旧版本,安装 TOMCAT 没有什么特别,只需下载并解压缩即可。

      获取并安装 JOTM:如果要使用 JOTM,只需要下载最近的二元版本并将解压缩即可。再从lib/ 目录下将.jar 文件(除了 log4j.jar、ommons-cli.jar 和 jotm_iiop_stubs.jar) 复制到 $CATALINA_HOME/shared/lib。这样就完成了。

      配置 TOMCAT:需要配置 Tomcat,使之能够从 JNDI 获取 UserTransaction 和 DataSource 对象(它们用在 foo.BankAccount 和 bar.ATM)。

      首先,告诉 TOMCAT 你所使用的 JNDI 名字,以便在 WEB 应用程序中查询数据源。这些步骤由 web.xml 完成,其代码如下。对于银行帐户数据源,使用的 JNDI 名字是 java:comp/env/jdbc/bankAccount ,而且只能在 java:comp/env/ 之后给出名字。TOMCAT 通过 JNDI 机制来解决其余的问题。对于 ATM 数据源也同样于此。

    例 4. web.xml

          <web-app>
    <resource-env-ref>
    <description>Bank Account DataSource</description>
    <resource-env-ref-name>jdbc/bankAccount</resource-env-ref-name>
    <resource-env-ref-type>javax.sql.DataSource</resource-env-ref-type>
    </resource-env-ref>
    
    <resource-env-ref>
    <description>ATM DataSource</description>
    <resource-env-ref-name>jdbc/ATM</resource-env-ref-name>
    <resource-env-ref-type>javax.sql.DataSource</resource-env-ref-type>
    </resource-env-ref>
    </web-app>

      您必须告诉 TOMCAT 怎么样返回 web.xml内的资源,这个过程就由bank.xml文件来完成了。对于银行帐户和 ATM 资源,您必须设置参数,以便 TOMCAT 能将 WEB 应用程序与数据源正确相连。有关更多的详细信息,请参考 TOMCAT JNDI 数据源基础知识。(参见 Resources)

      其中一个参数需特别关注:factory.类中设置这个参数,用于当 WEB 应用程序通过 JNDI 查询时来创建一个数据源。另外一个重要的资源(在 web.xml 中有描述)是 UserTransaction。java:comp/UserTransaction 使用这个资源来区分事务,它由 JOTM 来执行。

    例 5 bank.xml

          <Context path="/bank" docBase="bank.war" debug="0" 
    reloadable="true" crossContext="true">
    
    <!-- Description of the DataSource "jdbc/bankAccount" -->
    <Resource name="jdbc/bankAccount" auth="Container" 
     type="javax.sql.DataSource" />
    <ResourceParams name="jdbc/bankAccount">
    <parameter>
    <!-- Factory of the DataSource -->
    <name>factory</name>
    <value>org.objectweb.jndi.DataSourceFactory</value>
    </parameter>
    <parameter>
    <name>url</name>
    <value>jdbc:mysql://localhost/banktest</value>
    </parameter>
    <!-- other parameters include:
    o username - name of database user
    o password - password of the database user
    o driverClassName - JDBC Driver name
            -->
            ...
    </ResourceParams>
    
    <!-- Description of the DataSource "jdbc/ATM" -->
    <Resource name="jdbc/ATM" auth="Container" 
     type="javax.sql.DataSource" />
    
    <!-- same type of parameters than for resource 
     "jdbc/bankAccount" -->
    <ResourceParams name="jdbc/ATM">
            ...
    </ResourceParams>
    
    <!-- Description of the resource "UserTransaction -->
    <Resource name="UserTransaction" auth="Container" 
     type="javax.transaction.UserTransaction" />
    <ResourceParams name="UserTransaction">
    <parameter>
    <name>factory</name>
    <value>org.objectweb.jotm.UserTransactionFactory</value>
    </parameter>
    <parameter>
    <name>jotm.timeout</name>
    <value>60</value>
    </parameter>
    </ResourceParams>
    </Context>

      展开 WEB 应用程序:一旦你设置了 JOTM 和TOMCAT ,展开并使用 WEB 应用程序就很容易了。首先,下载 bank.tgz 并将之解压缩, 再将bank.xml 和 bank.war 复制到 $CATALINA_HOME/webapps 下;然后,启动 TOMCAT:

          > cd $CATALINA_HOME/bin
    > ./catalina.sh run
    Using CATALINA_BASE:/home/jmesnil/lib/tomcat
    Using CATALINA_HOME:/home/jmesnil/lib/tomcat
    Using CATALINA_TMPDIR:/home/jmesnil/lib/tomcat/temp
    Using JAVA_HOME:/usr/local/java
    May 6, 2003 5:56:00 PM org.apache.commons.modeler.Registry loadRegistry
    INFO:Loading registry information
    May 6, 2003 5:56:00 PM org.apache.commons.modeler.Registry 
     getRegistry
    INFO:Creating new Registry instance
    May 6, 2003 5:56:00 PM org.apache.commons.modeler.Registry 
     getServer
    INFO:Creating MBeanServer
    May 6, 2003 5:56:07 PM org.apache.coyote.http11.Http11Protocol init
    INFO:Initializing Coyote HTTP/1.1 on port 8080
    Starting service Tomcat-Standalone
    Apache Tomcat/4.1.24-LE-jdk14

    您会在日志里面发现 JOTM 还没有启动。它是在当您第一次访问 DataSource 时才会启动的,在那个时候,您将会发现以下信息:

          May 6, 2003 5:56:20 PM org.objectweb.jotm.Jotm <init>
    INFO:JOTM started with a local transaction factory that 
     is not bound.
    May 6, 2003 5:56:20 PM org.objectweb.jotm.Jotm <init>
    INFO:CAROL initialization

    键入URLhttp://localhost:8080/bank/来使用 WEB 应用程序。

      使用 WEB 应用程序

      WEB 应用程序的首页包含两个链接:

      1. 是 Cash Delivery 页面,您可以在上面像在 ATM 一样提款。

     

    图2 Cash Delivery 页面

      2. 是management console,您在上面可以对 ATM 或自己创建的银行帐户进行检测或更新。

     

    图3 Management Console

    操作之前,ATM 有$500,John Doe 银行帐户上有 $100 ,Jane Doe 银行帐户有 $600 。

    如果 John Doe想取 $400 ,交易将会失败,因为在他的帐户上余额不够。结果将是:

    Client ID:john_doe, value: $400

    Cash can not be delivered to you

    because:not enough money in your account (only $100).

    如果 Jane Doe想取 $550 ,交易也会失败,因为ATM上的现金不够。结果将是:

    Client ID:jane_doe, value: $550

    Cash can not be delivered to you

    because:not enough cash available from this ATM (only $500).

    如果 John Doe 取 $50 的话,交易将会成功。结果将是:

    Client ID:john_doe, value: $50

    Please take your cash ($50)

    Thank you!

      总结

      这个简单的例子证明了 servlet 是怎样通过使用事务提供健壮和简化的,并且确保在任何情况下都正确。Tomcat 和 JOTM 完美的结合使在 servlet 内能轻而易举的取得事务的优势。

      除上述简单的例子以外,JOTM还有更多的优点。JOTM 提供了以下性能,有助于增强 WEB 应用程序。

      1.完全分布式事务支持.如果数据层、业务层、表示层运行在不同的 JVM 上,则有可能有一个全程的事务跨度这些JVM,事务的内容在 RMI/JRMP 和 RMI/IIOP 上传播。

      2.整合 JDBC。使用的 XAPool例子就是一个 XA-兼容的 JDBC 连接池,可以与数据库相互操作。XAPool 类似于 Jakarta DBCP,只是增加了 XA-兼容的特征,如果要结合 JDBC 使用 JTA 事务就必须遵从这个特征。

      3.整合 JMS。JOTM 可以结合 JORAM,由ObjectWeb 协会开发的“JMS 提供者”提供了事务的 JMS 消息。你可以得到出现在 servlet中同一事务的 JMS 消息发送件和更新的数据库。

      4.WEB 服务事务。JOTM 提供了BTP(Business Transaction Protocol)、JOTM-BTP接口,它们用于在 WEB 服务中增加事务行为。

      所有这些功能的样例和文档都可以在 JOTM 的档案和网站上找到。

    展开全文
  • java servlet和jsp的概念及区别

    万次阅读 多人点赞 2017-02-25 13:05:59
    林炳文Evankaka原创作品。...一了解Servlet的概念二Servlet技术功能三 Servlet技术特点四 Servlet生命周期五servlet工作过程六 Servlet与JSP区别七Servlet代码结构八 Servlet第一个程序 一、了解Servlet的概念
  • 项目如何配置事务

    千次阅读 2019-11-05 18:07:39
    项目使用事务有好几种方式,本文章的项目都是使用的Spring,如果你使用的是JDBC编程,那么请看这个。 事务管理是应用系统开发必不可少的一部分。Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为 ...
  • 其中,加载Servlet程序的过程:根据Servlet容器与Servlet程序间的契约,当有请求过来时,如果Servlet程序还没有被载入Servlet容器,这个时候Servlet容器就会通过调用init()方法将Servlet类载入内存,并产生...
  • SIP Servlet是Java标准化机构JCP...SIPServlet容器的核心是SIP协议栈,容器负责接受和发送SIP消息,管理SIP对话和事务,实现SIP的核心语义。当容器收到消息时,将调用相应的SIP应用,同时SIP应用也会调用容器来发送消息。
  • Servlet常见面试题

    千次阅读 2019-03-05 23:28:31
    Servlet中的session的工作原理,以及设置过期时间的方式 Servlet中的filter的应用场景 JSP的动态include和静态include web.xml的作用 Servlet的线程安全问题 Servlet的概念,JSP与Servlet的区别 servlet是...
  • servlet面试常问问题Servlets is a very important topic of Java EE and all of the web applications frameworks such as Spring and Struts is built on top of it. This makes servlet interview questions a ...
  • 静态网页和动态网页、servlet容器与Web Server关系、Servlet Container工作过程、Servlet生命周期(init、service、destroy)
  • BESAppServer中Servlet3.0开发使用

    千次阅读 2016-05-09 13:02:48
    1.1 Servlet 1.1.1 Servlet简介 Servlet是运行在Web服务器的Java小程序。Servlet 3.0规范定义了ServletAPI的...Servlet是BES应用服务器运行的Java类,使用BES应用服务器运行的Servlet可以执行以下操作: 1. 创
  • Servlet的使用

    千次阅读 2019-12-15 11:02:09
    Servlet 回顾 1、Tomcat的配置 2、Web项目结构 今日内容 1、Servlet概念和入门 2、Servlet获取请求参数 3、Servlet的生命周期 4、Servlet的两种创建方式 5、Servlet的两种配置方式 6、Servlet线程安全 教学目标 1...
  • servlet ppt

    2008-09-10 10:02:53
    Servlet技术为Web开发者提供了一种简便、可靠的机制来扩展Web服务器的功能和访问现有的事务系统,Servlet是快速、高效地开发Web动态网站的工具。JSP+Servlet技术使服务器端动态页面程序可以真正地做到跨平台,因此,...
  • 【经典】servlet中常见的问题与解答

    千次阅读 2014-01-30 14:47:33
    这使得servlet成为java面试的一个热门话题。 这里笔者罗列了一些常见的跟servlet相关的面试问题与解答,希望能够帮助大家: 1.web服务器(web server)和应用服务器(appliction server)的区别是什么? ...
  • servlet web.xml配置选项详解

    万次阅读 2018-10-31 19:52:58
    一般的web工程中都会用到web.xml,web.xml主要包括一些配置标签,例如Filter、Listener、Servlet等,可以用来预设容器的配置,可以方便的开发web工程。但是web.xml并不是必须的,一个web工程可以没有web.xml文件 &...
  • JAVA项目事务管理

    千次阅读 2017-11-08 12:06:00
    事务:保证一组对数据库操作动作的完整性(一致性, 安全性),也就是说:这一组动作要么都成功,要么都失败 1.JDBC对事务的支持 JDBC 事务是用 Connection 对象控制的 JDBC Connection 接口( java.sql....
  • controller与servlet区别

    2021-03-19 12:17:03
    理解1: 你可以理解为,Spring MVC是基于servlet的,它有一个DispatherServlet,然后它负责处理请求,并且调用了你的controller。...而且基于Spring易实现事务控制和AOP 有问springmvc和servlet的区别的么?
  • 基于JSP+Servlet校园二手交易平台

    千次阅读 2021-03-29 16:03:03
    基于JSP/Servlet校园二手交易平台 摘 要 本系统采用JSP/servlet技术,是使用Java编程语言编写的一套校园网二手交易平台软件。系统采用的是最近几年流行的B/S开发模式,以互联网方式运行,服务器端只需要安装本系统,...
  • servlet

    千次阅读 2016-12-16 13:16:12
    1:为什么要出现JSP跟servlet? 前言:JSP跟servlet技术是用来开发动态网页的web技术;JSP在本质上就是一个servletservlet在本质上就是一个Java类; (1) 除了Linux,unix操作系统之外,当前windows操作使用数量...
  • Java Servlet 学习课件

    2011-04-27 15:24:11
    Java Servlet 学习课件 Java Servlet 学习课件
  • Servlet

    千次阅读 2017-10-27 22:56:03
    1、ServletServlet 运行在服务端的Java小程序,是sun公司提供一套规范(接口),用来处理客户端请求、响应给浏览器的动态资源。但servlet的实质就是java代码,通过java的API 动态的向客户端输出内容。servlet规范:...
  • 本系列文章是作者暑假给学生进行实训分享的笔记,主要介绍MyEclipse环境下JSP网站开发,包括JAVA基础、网页布局、数据库基础、Servlet、前端后台数据库交互、DAO等知识。 前一篇文章讲解了MyEclipse环境下创建JSP...
  • Javaweb阶段:dao+service+servlet开发流程

    千次阅读 2020-05-17 14:39:06
    // 将创建的conn存入到当前线程 tol.set(conn); } return conn; } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("获取连接失败!·"); } } ...
  • 在IEDA创建项目。 项目搭建准备工具 Tomcat tomcat下载地址:https://tomcat.apache.org/。 将tomcat下载之后,解压放在磁盘的一个目录下方。其目录结构如下: 项目搭建步骤 一、创建项目 在File下选中New...
  • 详解Hibernate事务

    千次阅读 2015-08-18 10:30:15
    上一篇博客讲解了Hibernate的一级缓存,属于Session级别的,这篇博客讲解一下Hibernate事务机制。有关事务的概念,请参照通俗易懂数据库事务。  2.如何处理Hibernate事务 我们知道数据库事务...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 108,972
精华内容 43,588
关键字:

servlet中如何开始事务