JavaWeb 后端 <十> 之 数据池 C3P0 DPCB JNDI

一、数据库连接池原理:(理解)

//模拟数据库连接池的原理
public class ConnectionPoolDemo {
	private static List<Connection> pool = new ArrayList<Connection>();
	static{
		try {
			for(int i=0;i<10;i++){
				Connection conn = JdbcUtil.getConnection();//创建的新连接
				pool.add(conn);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	//从池中取出一个链接
	public synchronized static Connection getConnection(){
		if(pool.size()>0){
			Connection conn = pool.remove(0);
			return conn;
		}else{
			throw new RuntimeException("服务器真忙");
		}
	}
	//把链接还回池中
	public static void release(Connection conn){
		pool.add(conn);
	}

}

二、编写数据源(DataSource)(很重要)

编写一个类实现javax.sql.DataSource

public class MyDataSource1 implements DataSource {

	private static List<Connection> pool = Collections.synchronizedList(new ArrayList<Connection>());
	static{
		try {
			for(int i=0;i<10;i++){
				Connection conn = JdbcUtil.getConnection();//创建的新连接
				pool.add(conn);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	//从池中获取链接  >  com.mysql.jdbc.Connection
	public Connection getConnection() throws SQLException {
		if(pool.size()>0){
			Connection conn = pool.remove(0);
			MyConnection1 mconn = new MyConnection1(conn,pool);
			return mconn;
		}else{
			throw new RuntimeException("服务器真忙");
		}
	}

	public PrintWriter getLogWriter() throws SQLException {
		return null;
	}

	public void setLogWriter(PrintWriter out) throws SQLException {

	}

	public void setLoginTimeout(int seconds) throws SQLException {

	}

	public int getLoginTimeout() throws SQLException {
		return 0;
	}

	public <T> T unwrap(Class<T> iface) throws SQLException {
		return null;
	}

	public boolean isWrapperFor(Class<?> iface) throws SQLException {
		return false;
	}

	public Connection getConnection(String username, String password)
			throws SQLException {
		return null;
	}

}

三、编程的难点:(设计模式)

难点:用一个实现了javax.sql.DataSource类的实例时,用户如果调用Connection.close()方法,会把链接关闭,失去了连接池的意义。

明确一个问题:用户得到Connection的实现是:数据库驱动对Connection接口的实现。因此,调用的close方法都是数据库驱动的,它会把链接给关闭。(这不是我们要的,我们要把该链接换回池中)。

解决方案:改写驱动原有的close方法。对已知类的某个/某些方法进行功能上的改变,有以下几种编码方案:

a、继承:此处行不通。

到底针对哪个驱动的实现写子类(很多)

数据库驱动对Connection接口的实现类,不允许被继承

丢失了原有对象的信息。捡了芝麻丢了西瓜。

b、装饰(包装)设计模式:(基础IO)

保持被包装对象的原有信息,又可以对某个/某些方法进行改写。

口诀:

1、编写一个类,实现与被包装类(数据库驱动对Connection的实现)相同的接口。(使这个类和数据库的驱动实现有着相同的行为)

2、定义一个变量,引用被包装类的实例。

3、定义构造方法,传入被包装类的实例。

4、对于要改写的方法,编写自己的代码即可。

5、对于不需要改写的方法,调用原有对象的对应方法。

//目前要包装的是:com.mysql.jdbc.Connection

//1、编写一个类,实现与被包装类(数据库驱动对Connection的实现)相同的接口。(使这个类和数据库的驱动实现有着相同的行为)
public class MyConnection implements Connection {
//	2、定义一个变量,引用被包装类的实例
	private Connection conn;//引用具体的数据库驱动

	private List<Connection> pool;

//	3、定义构造方法,传入被包装类的实例。
	public MyConnection(Connection conn,List<Connection> pool){//依赖注入
		this.conn = conn;
		this.pool = pool;
	}
	//把链接还回池中
//	4、对于要改写的方法,编写自己的代码即可。
	public void close() throws SQLException {
		pool.add(conn);
	}
	public Statement createStatement() throws SQLException {
		return conn.createStatement();
	}
	//5、对于不需要改写的方法,调用原有对象的对应方法。
	public <T> T unwrap(Class<T> iface) throws SQLException {
		return conn.unwrap(iface);
	}

c、默认适配器:(为了后来做准备)

//默认的适配器
/*
本身也是一个包装类,但并没有对任何的方法进行改写
1、编写一个类,实现与被包装类(数据库驱动对Connection的实现)相同的接口。(使这个类和数据库的驱动实现有着相同的行为)
2、定义一个变量,引用被包装类的实例。
3、定义构造方法,传入被包装类的实例。
4、全部调用原有对象的对应方法
 */
public class ConnectionAdapter implements Connection {
	private Connection conn;
	public ConnectionAdapter(Connection conn){
		this.conn = conn;
	}
	public <T> T unwrap(Class<T> iface) throws SQLException {
		return conn.unwrap(iface);
	}

	public boolean isWrapperFor(Class<?> iface) throws SQLException {
		return conn.isWrapperFor(iface);
	}
/*
这也是包装:对ConnectionAdapter进行包装。

包装类即是被包装类的包装,又是他的子类。

1、编写一个类,继承已经是包装类的类。
2、定义一个变量,引用被包装类的实例。
3、定义构造方法,传入被包装类的实例。
4、覆盖掉需要改写的方法
 */
public class MyConnection1 extends ConnectionAdapter {
	private Connection conn;
	private List<Connection> pool;
	public MyConnection1(Connection conn,List<Connection> pool){
		super(conn);
		this.conn = conn;
		this.pool = pool;
	}
	public void close() throws SQLException {
		pool.add(conn);
	}

}

d、动态代理:(很重要 AOP--Aspect-Oriented Programming 核心技术)

l  基于接口的动态代理:Proxy

如果一个类没有实现任何的接口,此种代理就不能使用了。

package com.itheima.proxy;

public interface Human {
	void sing(float money);
	void dance(float money);
}
package com.itheima.proxy;

public class SpringBrother implements Human {

	public void sing(float money) {
		System.out.println("拿到钱:"+money+"开唱");
	}

	public void dance(float money) {
		System.out.println("拿到钱:"+money+"开跳");
	}

}
package com.itheima.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Client1 {

	public static void main(String[] args) {
		final Human sb = new SpringBrother();

		//代理人:如何动态产生代理人

		/*
		ClassLoader loader:动态代理,必须有字节码class。加到内存中运行,必须有类加载器。固定:和被代理人用的是一样的
        Class<?>[] interfaces:代理类要实现的接口,要和被代理对象有着相同的行为。固定:和被代理人用的是一样的
        InvocationHandler h:如何代理。他是一个接口。策略设计模式。

		 */
		//产生代理类,得到他的实例
		Human proxyMan = (Human)Proxy.newProxyInstance(sb.getClass().getClassLoader(),
				sb.getClass().getInterfaces(),
				new InvocationHandler() {
					//匿名内部类,完成具体的代理策略
					//调用代理类的任何方法,都会经过该方法。  拦截

					/*
					 Object proxy:对代理对象的引用。
					 Method method:当前执行的方法
					 Object[] args:当前方法用到的参数

					 返回值:当前调用的方法的返回值
					 */
					public Object invoke(Object proxy, Method method, Object[] args)
							throws Throwable {
						//判断出场费
						if("sing".equals(method.getName())){
							//唱歌
							float money = (Float)args[0];
							if(money>10000){
								method.invoke(sb, money/2);
							}
						}
						if("dance".equals(method.getName())){
							//唱歌
							float money = (Float)args[0];
							if(money>20000){
								method.invoke(sb, money/2);
							}
						}
						return null;
					}
				}
		);
		proxyMan.sing(20000);
		proxyMan.dance(100000);
	}

}

l  基于子类的动态代理:CGLIB

前提:被代理类的要求

1、不能是final的

2、必须是public的

package com.itheima.cglib;

public class SpringBrother{

	public void sing(float money) {
		System.out.println("拿到钱:"+money+"开唱");
	}

	public void dance(float money) {
		System.out.println("拿到钱:"+money+"开跳");
	}

}
package com.itheima.cglib;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class Client1 {

	public static void main(String[] args) {

		final SpringBrother sb = new SpringBrother();

		//产生sb的代理:
		/*
		Class type:代理类的父类型
		Callback cb:回调,如何代理
		 */
		SpringBrother proxy = (SpringBrother) Enhancer.create(SpringBrother.class,new MethodInterceptor(){

			public Object intercept(Object proxy, Method method, Object[] args,
					MethodProxy arg3) throws Throwable {
				//判断出场费
				if("sing".equals(method.getName())){
					//唱歌
					float money = (Float)args[0];
					if(money>10000){
						method.invoke(sb, money/2);
					}
				}
				if("dance".equals(method.getName())){
					//唱歌
					float money = (Float)args[0];
					if(money>20000){
						method.invoke(sb, money/2);
					}
				}
				return null;
			}
		});
		System.out.println(proxy instanceof SpringBrother);
		proxy.dance(100000);
		proxy.sing(50000);

	}

}

比如普通的JavaBean就可能没有实现任何的接口。代理类是被代理类的子类。

四、开源数据源的使用:(很重要,非常简单)

1、DBCP:

Apache组织开发的。DBCP:DataBase Connection Pool,对数据源的一种实现。

a、拷贝jar包

b、编写配置文件

dbcpconfig.properties

#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=root
password=sorry

#<!-- 初始化连接 -->
initialSize=10

#最大连接数量
maxActive=50

#<!-- 最大空闲连接 -->
maxIdle=20

#<!-- 最小空闲连接 -->
minIdle=5

#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000

#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=utf8

#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true

#driver default 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=

#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=REPEATABLE_READ

c、使用即可

public class DBCPUtil {
	private static DataSource dataSource;
	static{
		try {
			InputStream in = DBCPUtil.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
			Properties props = new Properties();
			props.load(in);
			dataSource = BasicDataSourceFactory.createDataSource(props);
		} catch (Exception e) {
			throw new ExceptionInInitializerError(e);
		}
	}

	public static DataSource getDataSource(){
		return dataSource;
	}

	public static Connection getConnection(){
		try {
			return dataSource.getConnection();
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}
}

2、C3P0:

开源数据源的实现。

c3p0-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
	<default-config>
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql:///test</property>
		<property name="user">root</property>
		<property name="password">sorry</property>
		<property name="initialPoolSize">10</property>
		<property name="maxIdleTime">30</property>
		<property name="maxPoolSize">100</property>
		<property name="minPoolSize">10</property>
		<property name="maxStatements">200</property>
	</default-config>
	<named-config name="day15">
		<property name="initialPoolSize">10</property>
		<property name="maxIdleTime">30</property>
		<property name="maxPoolSize">100</property>
		<property name="minPoolSize">10</property>
		<property name="maxStatements">200</property>
	</named-config>
</c3p0-config>
public class C3P0Util {
	private static ComboPooledDataSource dataSource = new ComboPooledDataSource();

	public static DataSource getDataSource(){
		return dataSource;
	}

	public static Connection getConnection(){
		try {
			return dataSource.getConnection();
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}
}

3、更接近实际开发:JNDI管理数据源

JNDI:Java Naming and Directory Interface。属于JavaEE技术之一,目的模仿window系统中的注册表。

a、在服务器中注册JNDI数据源

1、拷贝数据库的驱动到Tomcat\lib目录下

2、在web应用的META-INF目录下建立一个名称为context.xml的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<Context>
	<Resource name="jdbc/test" auth="Container" type="javax.sql.DataSource"
               maxActive="20" maxIdle="5" maxWait="10000"
               username="root" password="sorry" driverClassName="com.mysql.jdbc.Driver"
               url="jdbc:mysql://localhost:3306/test"/>
</Context>

3、获取JNDI容器中的资源

public class JndiDsUtil {
	public static Connection getConnection() throws Exception {
		Context initContext = new InitialContext();
		DataSource ds = (DataSource) initContext
				.lookup("java:/comp/env/jdbc/test");
		Connection conn = ds.getConnection();
		return conn;
	}
}

五、编写自己的JDBC框架(为学习DBUtil框架、Spring JDBCTemplate做准备)

1、数据库元信息的获取(为写框架而准备)

元信息:数据库的一些定义信息。比如用的是什么数据库等,表的定义信息等。

DatabaseMetaData    PreparedStatement    ResultSetMetaData getColumnCount

//数据库元信息的获取
public class Demo {
	//数据库本身信息的获取
	@Test
	public void test1() throws Exception{
		Connection conn = DBCPUtil.getConnection();
		DatabaseMetaData dmd = conn.getMetaData();
		String name = dmd.getDatabaseProductName();//能知道说什么方言
		System.out.println(name);
		int isolation = dmd.getDefaultTransactionIsolation();
		System.out.println(isolation);
	}
	//参数元数据信息:PreparedStatement时
	@Test
	public void test2() throws Exception{
		Connection conn = DBCPUtil.getConnection();
		PreparedStatement stmt = conn.prepareStatement("??????????");

		ParameterMetaData pmd = stmt.getParameterMetaData();
		int count = pmd.getParameterCount();
		System.out.println(count);//统计语句中的占位符个数
	}
	//结果集元数据信息:
	@Test
	public void test3()throws Exception{
		Connection conn = DBCPUtil.getConnection();
		PreparedStatement stmt = conn.prepareStatement("select * from account");
		ResultSet rs = stmt.executeQuery();
		ResultSetMetaData rsmd = rs.getMetaData();
		int count = rsmd.getColumnCount();//有几列
		System.out.println(count);

		for(int i=0;i<count;i++){
			String fieldName = rsmd.getColumnName(i+1);
			int type = rsmd.getColumnType(i+1);
			System.out.println(fieldName+":"+type);
		}
	}
}

2、编写JDBC框架:(策略设计模式)

/**
 * 框架的核心类
 * @author wzhting
 *
 */
public class DBAssist {
	private DataSource dataSource;
	public DBAssist(DataSource dataSource){
		this.dataSource = dataSource;
	}
	//写:添加、删除、修改
	//params参数要和sql中的占位符对应
	public void update(String sql,Object...params) {
		Connection conn = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try{
			conn = dataSource.getConnection();
			stmt = conn.prepareStatement(sql);
			//设置参数
				//得到sql中的参数
				ParameterMetaData pmd = stmt.getParameterMetaData();
				int count = pmd.getParameterCount();
				if(count>0){
					if(params==null){
						throw new RuntimeException("必须传入参数的值");
					}
					if(count!=params.length){
						throw new RuntimeException("参数数量不匹配");
					}
					for(int i=0;i<count;i++){
						stmt.setObject(i+1, params[i]);
					}

				}

			stmt.executeUpdate();
		}catch(Exception e){
			throw new RuntimeException(e);
		}finally{
			release(rs, stmt, conn);
		}
	}

	//读:查询
	public Object query(String sql,ResultSetHandler rsh,Object...params) {
		Connection conn = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try{
			conn = dataSource.getConnection();
			stmt = conn.prepareStatement(sql);
			//设置参数
				//得到sql中的参数
				ParameterMetaData pmd = stmt.getParameterMetaData();
				int count = pmd.getParameterCount();
				if(count>0){
					if(params==null){
						throw new RuntimeException("必须传入参数的值");
					}
					if(count!=params.length){
						throw new RuntimeException("参数数量不匹配");
					}
					for(int i=0;i<count;i++){
						stmt.setObject(i+1, params[i]);
					}

				}

			rs = stmt.executeQuery();
			//有结果集,要封装到对象中。策略设计模式
			return rsh.handle(rs);
		}catch(Exception e){
			throw new RuntimeException(e);
		}finally{
			release(rs, stmt, conn);
		}
	}

	private void release(ResultSet rs,Statement stmt,Connection conn){
		if(rs!=null){
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			rs = null;
		}
		if(stmt!=null){
			try {
				stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			stmt = null;
		}
		if(conn!=null){
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			conn = null;
		}
	}
}
public interface ResultSetHandler {
	/**
	 * 把结果中的数据封装到指定的对象中
	 * @param rs
	 * @return 封装了数据的对象
	 */
	Object handle(ResultSet rs);
}
/**
 * 适合只有一条查询结果的情况
 * 封装到JavaBean中
 * 满足约定:数据库字段名和JavaBean字段名保持一致
 * @author wzhting
 *
 */
public class BeanHanlder implements ResultSetHandler {

	private Class clazz;//目标类型
	public BeanHanlder(Class clazz){
		this.clazz = clazz;
	}

	public Object handle(ResultSet rs) {
		try {
			if(rs.next()){
				//有记录
				Object bean = clazz.newInstance();//目标对象
				//有多少列,列名和值又是什么?
				ResultSetMetaData rsmd = rs.getMetaData();
				int count = rsmd.getColumnCount();//列数
				for(int i=0;i<count;i++){
					String fieldName = rsmd.getColumnName(i+1);//得到数据库字段名,也就得到了JavaBan的字段名
					Object fieldValue = rs.getObject(fieldName);//字段值
					//通过字段反射
					Field f = clazz.getDeclaredField(fieldName);
					f.setAccessible(true);
					f.set(bean, fieldValue);
				}
				return bean;
			}
			return null;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

}
/**
 * 封装到JavaBean中
 * 满足约定:数据库字段名和JavaBean字段名保持一致
 * @author wzhting
 *
 */
public class BeanListHanlder implements ResultSetHandler {

	private Class clazz;//目标类型
	public BeanListHanlder(Class clazz){
		this.clazz = clazz;
	}

	public Object handle(ResultSet rs) {
		try {
			List list = new ArrayList();
			while(rs.next()){
				//有记录
				Object bean = clazz.newInstance();//目标对象
				//有多少列,列名和值又是什么?
				ResultSetMetaData rsmd = rs.getMetaData();
				int count = rsmd.getColumnCount();//列数
				for(int i=0;i<count;i++){
					String fieldName = rsmd.getColumnName(i+1);//得到数据库字段名,也就得到了JavaBan的字段名
					Object fieldValue = rs.getObject(fieldName);//字段值
					//通过字段反射
					Field f = clazz.getDeclaredField(fieldName);
					f.setAccessible(true);
					f.set(bean, fieldValue);
				}
				list.add(bean);
			}
			return list;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

}
时间: 2024-10-10 00:08:33

JavaWeb 后端 <十> 之 数据池 C3P0 DPCB JNDI的相关文章

JavaWeb 后端 &lt;十四&gt; 文件上传下载

1.文件上传与下载 案例: 注册表单/保存商品等相关模块! --à 注册选择头像 / 商品图片 (数据库:存储图片路径 / 图片保存到服务器中指定的目录) 1.1 文件上传 文件上传,要点: 前台: 1. 提交方式:post 2. 表单中有文件上传的表单项: <input type=”file” /> 3. 指定表单类型: 默认类型:enctype="application/x-www-form-urlencoded" 文件上传类型:enctype =”multipart/

JavaWeb 后端 &lt;十二&gt; 之 过滤器 filter 乱码、不缓存、脏话、标记、自动登录、全站压缩过滤器

一.过滤器是什么?有什么? 1.过滤器属于Servlet规范,从2.3版本就开始有了. 2.过滤器就是对访问的内容进行筛选(拦截).利用过滤器对请求和响应进行过滤 二.编写步骤和执行过程 1.编码步骤: a.编写一个类:实现javax.servlet.Filter接口 public class FilterDemo1 implements Filter { public FilterDemo1(){ System.out.println("调用了默认的构造方法"); } //用户每次访

javaweb学习总结(三十九)——数据库连接池

一.应用程序直接获取数据库连接的缺点 用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长.假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出.拓机.如下图所示: 二.使用数据库连接池优化程序性能 2.1.数据库连接池的基本概念 数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现的尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性

数据库连接池c3p0

一.概述: 数据库连接池C3P0框架是个非常优异的开源jar,高性能的管理着数据源,c3p0有两种数据源管理方式,一种是通过程序变本身来进行管理,还有一种是通过容器管理,本节讨论通过程序本身来进行管理,下一节讨论通过容器进行管理. 二.c3p0的三种实现方式 1.实现方式一:利用c3p0的API自己动手写代码,实现数据源 例如:在类路径下配置一个属性文件,config.properties,内容如下: Java代码   driverClass=xxx jdbcUrl=xxx user=xxx p

JavaWeb 后端 &lt;二&gt; 之 Servlet 学习笔记

JavaWeb 后端 <二> 之 Servlet 学习笔记 一.Servlet概述 1.什么是Servlet Servlet是一个运行在服务器端的Java小程序,通过HTTP协议用于接收来自客户端请求,并发出响应. 2.Servlet中的方法 public void service(ServletRequest req,ServletResponse res) throws ServletException,java.io.IOException ServletRequest req:代表着请

数据库连接JDBC和数据库连接池C3P0自定义的java封装类

数据库连接JDBC和数据库连接池C3P0自定义的java封装类 使用以下的包装类都需要自己有JDBC的驱动jar包: 如 mysql-connector-java-5.1.26-bin.jar(5.1.26代表的是版本序列号) 一.JDBC的封装:(java连接MySQL) 1 import java.sql.*; 2 3 import utils.GlobalConstant; 4 5 public class JDBCUtil { 6 7 private JDBCUtil() { 8 9 }

数据库连接池C3P0学习

数据库连接池C3P0框架是个非常优异的开源jar,高性能的管理着数据源,这里只讨论程序本身负责数据源,不讨论容器管理. 一.实现方式: C3P0有三种方式实现: 1.自己动手写代码,实现数据源 例如:在类路径下配置一个属性文件,config.properties,内容如下: driverClass=xxx jdbcUrl=xxx user=xxx password=xxx ... 然后代码中实现 Properties props = new Properties(); InputStream i

网络协议 finally{ return问题 注入问题 jdbc注册驱动问题 PreparedStatement 连接池目的 1.2.1DBCP连接池 C3P0连接池 MYSQL两种方式进行实物管理 JDBC事务 DBUtils事务 ThreadLocal 事务特性 并发访问 隔离级别

1.1.1 API详解:注册驱动 DriverManager.registerDriver(new com.mysql.jdbc.Driver());不建议使用 原因有2个: >导致驱动被注册2次. >强烈依赖数据库的驱动jar 解决办法: Class.forName("com.mysql.jdbc.Driver"); 1.1.2 API详解:java.sql.Statement接口: 操作sql语句,并返回相应结果 String sql = "某SQL语句&qu

python之路---06 小数据池 编码

二十二.小数据池, id()    进行缓存 1.小数据池针对的是: int, str, bool 2.在py文件中几乎所有的字符串都会缓存.   在cmd命令窗口中几乎都不会缓存   不同的解释器有不同的机制 3.id() 查看变量的内存地址 4. is和==的区别 is 比较的是内存地址 == 比较的是内容 当两个变量指向同一个对象的时候. is是True, ==也是True 5. 优点:快速创建对象,节省内存 缺点:缓存如果过大,影响速度会比较慢 二十三. 再谈编码 回顾: 1. asci