JNDI连接数据库

本文涉及的产品
云数据库 RDS SQL Server,独享型 2核4GB
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 一、JNDI数据库连接通用数据访问层(JNDIDBManager) 代码下: package com.myphome.dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; impor

一、JNDI数据库连接通用数据访问层(JNDIDBManager)

代码下:

package com.myphome.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

/**
 * JNDI数据库连接通用数据访问层
 * */
public class JNDIDBManager {
 //mySql连接固定参数和数据源名称字符串(分为两部分"java:comp/env"为JavaEE默认路径,"jdbc/blog"为DataSource名)
 private static final String MYSQL_DATASOURCE_STRING="java:comp/env/jdbc/blog";
 //sqlserver连接固定参数和数据源名称字符串
 private static final String SQLSERVER_DATASOURCE_STRING="java:comp/env/googlesnack";
 //oracle连接固定参数和数据源名称字符串
 private static final String ORACLE_DATASOURCE_STRING="java:comp/env/users";
 
 //使用单例模式来保存数据库对象
 private static ThreadLocal<Connection> tlconn=new ThreadLocal<Connection>();
 /**
  * 获取JNDI连接数据库对象
  * @throws NamingException
  * @throws SQLException
  * */
 public Connection getConnection() throws NamingException, SQLException{
 /*
  * ThreadLocal类可以保存一个对象,只能保存一个, 调用get方法得到保存的对象, 调用set方法向ThreadLocal中保存对象
  * 调用remove()方法,将ThreadLocal中的对象移除
  * 如果ThreadLocal中保存了连接对象,就从ThreadLocal中获取连接对象
  * 如果ThreadLocal没有保存连接对象,就从连接池中获取一个连接对象,并把该连接对象保存到ThreadLocal中
  */
  //从ThreadLocal获取Connection对象
  Connection conn=tlconn.get();
  //如果ThreadLocal中存在连接对象,则返回连接对象
  if(conn!=null){
   return conn;
  }else{

  //否则从连接池中获取一个连接对象,然后将连接对象放到ThreadLocal中,并返回该连接对象
   //数据源DataSource由Tomcat提供,不能在程序中创建实例,并使用JNDI获得DataSource引用
   /*
    *JNDI(Java Naming and Directory Interface,Java命名和目录接口)是一组在Java应用中访问命名和目录服务的API
    *javax.namming.Context接口的lookup()方法
    */
   Context context=new InitialContext();
   /*
    *javax.sql.DataSource接口负责建立与数据库的连接
    *从Tomcat的数据源获得连接
    *把连接保存在连接池中
    */
   //mysql
   DataSource ds=(DataSource) context.lookup(MYSQL_DATASOURCE_STRING);
   //sqlserver
//   DataSource ds=(DataSource) context.lookup(SQLSERVER_DATASOURCE_STRING);

//   //oracle
//   DataSource ds=(DataSource) context.lookup(ORACLE_DATASOURCE_STRING);
   //获取连接对象
   conn=ds.getConnection();
   //将数据库连接对象放入到ThreadLocal中
   tlconn.set(conn);
   return conn;
  }
 }

 /**
  * 从ThreadLocal中移除连接对象,以免线程池误操作本地变量
  * */
 public void removeConnection()throws Exception {
  tlconn.remove();//将ThreadLocal中保存的连接对象移除,移除后tl.get()方法得到的结果是null
 }
 /**
  * 为sql语句占位符赋值
  * */
 private void operateParameters(PreparedStatement pstmt,Object ... args) throws SQLException {
    if (args != null && args.length > 0) {
        for (int i = 0; i < args.length; i++) {
            pstmt.setObject(i + 1, args[i]);
        }
   }
 }
 /**
  * 将结果集转换为实体对象的接口
  * Mapper接口用于规定将数据行转换为entity的方法,以Mapper结尾的类(如:ArticleMapper)是该接口的子类
  * Mapper子类用于将rs指向的数据行转换为指定的entity对象
  * */
 public static interface RowMapper<T> {
  public T rowMapper(ResultSet rs);
 }

 /**
  * 数据库查询方法
  * @return list<T>
  * 第二个参数rowmapper:明确由哪个类负责将数据行转换为entity对象
  * 第一个参数:sql语句
  * 第三个参数:sql语句参数的值
  * */
 public <T> List<T> executeQuery(String sql, RowMapper mapper,Object ... values) throws Exception{
  List list = new ArrayList<T>();
  Connection conn = null;
  PreparedStatement pstmt = null;
  ResultSet rs = null;
  try {
   conn = getConnection();
   pstmt = conn.prepareStatement(sql);
   operateParameters(pstmt, values);
   rs = pstmt.executeQuery();

   
   //将结果集一条记录转换为实体对象,并添加到集合中
   while (rs.next()) {
    T obj = (T) mapper.rowMapper(rs);
    list.add(obj);
   }
  } catch (SQLException e) {
   e.printStackTrace();
   throw new Exception("执行数据查询时,失败");
  } finally {
   //关闭rs
   closeResultSet(rs);
   //关闭pstmt
   closeStatement(pstmt);
   //注意,rs和pstmt是DBManager关闭的,conn是有调用DBManager类关闭的
  }
  return list;
 }

 /**
  * 数据库更新数据方法(添加、修改、删除)
  * @return int
  * */
 public int executeUpdate(String sql, Object...args) throws Exception {
  PreparedStatement pstmt = null;
  int rowCount = 0;
  Connection conn = getConnection();
  try {
   pstmt = conn.prepareStatement(sql);
   operateParameters(pstmt, args);
   rowCount = pstmt.executeUpdate();
  } catch (SQLException e) {
   e.printStackTrace();
   throw new Exception("更新数据失败");
  } finally {
   closeStatement(pstmt);
  }
  return rowCount;
 }
 /**
  * 执行聚合函数查询(求总和)
  * */
 public int executeScalar(String sql,Object ...values){
  Connection conn = null;
  PreparedStatement pstmt = null;
  ResultSet rs = null;
  try {
   conn = getConnection();
   pstmt = conn.prepareStatement(sql);
   operateParameters(pstmt, values);
   rs = pstmt.executeQuery();
   if(rs.next()){
    return rs.getInt(1);
   }
   return 0;
  }catch (Exception e) {
   return 0;
  }finally{
   closeResultSet(rs);
   closeStatement(pstmt);
  }
 }
 /**
  * 关闭连接
  *
  * @param dbConnection
  *            Connection
  */
 public void closeConnection() {
  try {
   Connection conn = tlconn.get();
   if (conn != null && (!conn.isClosed())) {
    //关闭连接对象
    conn.close();
    conn = null;

    //将连接对象从tl中移除
    tlconn.remove();
   }
  } catch (SQLException e) {
   e.printStackTrace();
  }

 }
 /**
  * 关闭结果集
  */
 public void closeResultSet(ResultSet rs) {
  try {
   if (rs != null) {
    rs.close();
    rs = null;
   }
  } catch (SQLException e) {
   e.printStackTrace();
  }
 }

 /**
  * 关闭语句
  */
 public void closeStatement(PreparedStatement pstmt) {
  try {
   if (pstmt != null) {
    pstmt.close();
    pstmt = null;
   }
  } catch (SQLException e) {
   e.printStackTrace();
  }
 }
 /**
  * 开始事务
  * */
 public void setAutoCommit()throws Exception {
  try {
   getConnection();
   
   //开始事务
   tlconn.get().setAutoCommit(false);
  } catch (SQLException e) {
   e.printStackTrace();
   throw new Exception("开始事务时,出现错误");
  }
 }
 /**
  * 提交事务
  * */
 public void commit() throws Exception {
  try {
   //提交事务
   tlconn.get().commit();
  } catch (SQLException e) {
   e.printStackTrace();
   throw new Exception("事务提交失败");
  }
 }
 /**
  * 回滚事务
  * */
 public void rollback() throws Exception{
  try {
   //回滚事务
   tlconn.get().rollback();
  } catch (SQLException e) {
   e.printStackTrace();
   throw new Exception("事务回滚失败");
  }
 }
}


二、将结果集rs指向的数据当前一行记录转换为指定的entity对象的mapper类(如:FoodMapper)

package com.myphome.mapper;
import java.sql.ResultSet;

import com.myphome.dao.JNDIDBManager;
import com.myphome.entity.Food;

/**
 *FoodMapper用于将界面需要的数据查询出来,然后将rs指向的一条记录转换为Food实体类
 */
public class FoodMapper implements JNDIDBManager.RowMapper<Food> {

 public Food rowMapper(ResultSet rs) {
  Food food = null;
  try {
   food = new Food();
   food.setAgio(rs.getDouble("agio"));
   food.setCharacteristics(rs.getString("characteristics"));
   food.setCuisine(null)
;//把其他实体类作为此对象属性赋值(用第二个sql查询赋值,即sql嵌套)
   food.setCuisineId(rs.getInt("cuisineId"));
   food.setEatery(null);
   food.setEateryId(rs.getInt("eateryId"));
   food.setFingredient(rs.getString("fingredient"));
   food.setId(rs.getInt("id"));
   food.setImg(rs.getString("img"));
   food.setIntegral(rs.getInt("integral"));
   food.setName(rs.getString("name"));
   food.setPrice(rs.getDouble("price"));
   food.setRemark(rs.getString("remark"));
  } catch (Exception e) {
   food =null;
   e.printStackTrace();
  }
  return food;
 }
}
三、Food实体类

package com.myphome.entity;

import java.io.Serializable;

/**
 * 菜品
 */
public class Food implements Serializable{
 private int id; //食物的主键
 private String name;//食物的名称
 private String fingredient;//食物的配料
 private double price;//食物的价格
 private double agio;//食物的折扣
 private String remark;//食物的简介
 private String characteristics;//食物的特色
 private String img;//食物的图片
 private int integral;//购买食物所送积分
 
 private int cuisineId;//食物所属菜系的id
 private int eateryId;//食物所属餐馆的id
 
 //对象属性,菜系类
 private Cuisine cuisine;
 //对象属性,菜馆类
 private Eatery eatery;
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 /**
  * 获取配料
  * */
 public String getFingredient() {
  return fingredient;
 }
 
 /**
  * 设置配料
  * */
 public void setFingredient(String fingredient) {
  this.fingredient = fingredient;
 }
 public double getPrice() {
  return price;
 }
 public void setPrice(double price) {
  this.price = price;
 }
 public double getAgio() {
  return agio;
 }
 public void setAgio(double agio) {
  this.agio = agio;
 }
 public String getRemark() {
  return remark;
 }
 public void setRemark(String remark) {
  this.remark = remark;
 }
 /**
  * 获取特色
  * */
 public String getCharacteristics() {
  return characteristics;
 }
 /**
  * 设置特色
  * */
 public void setCharacteristics(String characteristics) {
  this.characteristics = characteristics;
 }
 public String getImg() {
  return img;
 }
 public void setImg(String img) {
  this.img = img;
 }
 /**
  * 获取积分
  * */
 public int getIntegral() {
  return integral;
 }
 
 /**
  * 设置积分
  * */
 public void setIntegral(int integral) {
  this.integral = integral;
 }
 public int getCuisineId() {
  return cuisineId;
 }
 public void setCuisineId(int cuisineId) {
  this.cuisineId = cuisineId;
 }
 public int getEateryId() {
  return eateryId;
 }
 public void setEateryId(int eateryId) {
  this.eateryId = eateryId;
 }
 public Cuisine getCuisine() {
  return cuisine;
 }
 public void setCuisine(Cuisine cuisine) {
  this.cuisine = cuisine;
 }
 public Eatery getEatery() {
  return eatery;
 }
 public void setEatery(Eatery eatery) {
  this.eatery = eatery;
 }
}
四、JNDI的配置步骤:

 

1.Tomcatconf/context.xml中的配置:

<Context>
 <!--**JNDI  DataSource数据源tomcat下配置**-->
 <!--sqlserver-->
 <Resource name="googlesnack" auth="Container" type="javax.sql.DataSource"
    maxActive="100" maxIdle="30" maxWait="10000"
    username="sa" password="sa" driverClassName="com.microsoft.jdbc.sqlserver.SQLServerDriver"
    url="jdbc:sqlserver://localhost:1433;DatabaseName=google_snack"/>
 <!--mysql-->
 <Resource name="jdbc/blog" auth="Container" type="javax.sql.DataSource"
  maxActive="100" maxIdle="30" maxWait="60000"
  username="root" password="root" driverClassName="org.gjt.mm.mysql.Driver"
  url="jdbc:mysql://localhost:3306/blog"/>
 <!--oracle-->
 <Resource name="users" auth="Container" type="javax.sql.DataSource"
  maxActive="100" maxIdle="30" maxWait="60000"
  username="kekeai" password="kekeai123" driverClassName="oracle.jdbc.driver.OracleDriver"
  url="jdbc:oracle:thin:@localhost:1521:orcl"/>
</Context>

  注:

2.加入数据库驱动文件:

把数据库驱动的.jar文件,加入到Tomcat下lib中。
 
3.(可省略) 应用程序的 web.xml 文件的配置,web.xml中配置<resource-ref>
 

注:如果用junit测试,将报错:

javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial

解决:用web项目形式测试,则成功!

 

 

//tomcat下context.xml 中有汉字将报编码错误。

//界面提交using POST method,则:this.dopost(request,response);

 

 

 

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
6天前
|
SQL 关系型数据库 MySQL
【Go语言专栏】使用Go语言连接MySQL数据库
【4月更文挑战第30天】本文介绍了如何使用Go语言连接和操作MySQL数据库,包括选择`go-sql-driver/mysql`驱动、安装导入、建立连接、执行SQL查询、插入/更新/删除操作、事务处理以及性能优化和最佳实践。通过示例代码,展示了连接数据库、使用连接池、事务管理和性能调优的方法,帮助开发者构建高效、稳定的Web应用。
|
3天前
|
NoSQL Shell MongoDB
NoSQL数据使用指令和引擎连接数据库实例
【5月更文挑战第8天】本文介绍了MongoDB的本地使用和常用操作,包括通过mongo shell连接数据库、显示数据库和集合,以及副本集设置。最后提到了MongoDB的日志功能和顶点集的使用,如capped collection的创建和管理。
45 3
|
3天前
|
Java 数据处理 流计算
实时计算 Flink版产品使用合集之可以通过JDBC连接器来连接Greenplum数据库吗
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
14 1
|
6天前
|
关系型数据库 MySQL 数据库
mysql 设置环境变量与未设置环境变量连接数据库的区别
设置与未设置MySQL环境变量在连接数据库时主要区别在于命令输入方式和系统便捷性。设置环境变量后,可直接使用`mysql -u 用户名 -p`命令连接,而无需指定完整路径,提升便利性和灵活性。未设置时,需输入完整路径如`C:\Program Files\MySQL\...`,操作繁琐且易错。为提高效率和减少错误,推荐安装后设置环境变量。[查看视频讲解](https://www.bilibili.com/video/BV1vH4y137HC/)。
91 3
mysql 设置环境变量与未设置环境变量连接数据库的区别
|
6天前
|
Oracle Java 关系型数据库
【服务器】python通过JDBC连接到位于Linux远程服务器上的Oracle数据库
【服务器】python通过JDBC连接到位于Linux远程服务器上的Oracle数据库
17 6
|
6天前
|
SQL Java 关系型数据库
【JAVA基础篇教学】第十六篇:Java连接和操作MySQL数据库
【JAVA基础篇教学】第十六篇:Java连接和操作MySQL数据库
|
6天前
|
SQL Java 数据库连接
Java数据库编程实践:连接与操作数据库
Java数据库编程实践:连接与操作数据库
12 0
|
6天前
|
关系型数据库 Java 数据库
docker部署postgresql数据库和整合springboot连接数据源
docker部署postgresql数据库和整合springboot连接数据源
22 0
|
6天前
|
SQL JSON 关系型数据库
[UE虚幻引擎插件DTPostgreSQL] PostgreSQL Connector 使用蓝图连接操作 PostgreSQL 数据库说明
本插件主要是支持在UE蓝图中连接和操作PostgreSQL 数据库。
20 2
|
6天前
|
Java 关系型数据库 数据库连接
【C 言专栏】C 语言与数据库的连接与操作
【5月更文挑战第2天】本文探讨了C语言如何连接和操作数据库,介绍了数据库连接的基本原理,如通过ODBC、JDBC或原生接口与数据库交互。文章详细阐述了使用ODBC连接的步骤,并列举了C语言在数据库操作中的常见任务,强调了错误处理、数据类型匹配和性能优化的重要性。通过实际案例,展示了在学生信息管理系统中应用C语言与数据库交互的过程。本文旨在帮助读者更好地理解和应用C语言进行数据库管理。