Mysql JDBC驱动源码分析(获取连接)二
setReadonly(true)
?概念:从这一点设置的时间点开始到这个事务结束的过程中,其他事务所提交的数据,该事务将看不见!(查询中不会出现别人在时间点a之后提交的数据)
应用场合:
如果你一次执行单条查询语句,则没有必要启用事务支持,数据库默认支持SQL执行期间的读一致性;?
如果你一次执行多条查询语句,例如统计查询,报表查询,在这种场景下,多条查询SQL必须保证整体的读一致性,否则,在前条SQL查询之后,后条SQL查询之前,数据被其他用户改变,则该次整体的统计查询将会出现读数据不一致的状态,此时,应该启用事务支持。
【注意是一次执行多次查询来统计某些信息,这时为了保证数据整体的一致性,要用只读事务】
怎样设置:
对于只读查询,可以指定事务类型为readonly,即只读事务。
由于只读事务不存在数据的修改,因此数据库将会为只读事务提供一些优化手段,例如Oracle对于只读事务,不启动回滚段,不记录回滚log。
?
?
当驱动加载完毕后,接下来就是怎样去获取一个连接
?
Drivermanager.getConnection(url,name,password)
?跟踪代码执行到以下一步
?
private static Connection getConnection(String url, java.util.Properties info, ClassLoader callerCL) throws SQLException {java.util.Vector drivers = null; /* * When callerCl is null, we should check the application's * (which is invoking this class indirectly) * classloader, so that the JDBC driver class outside rt.jar * can be loaded from here. */synchronized(DriverManager.class) { // synchronize loading of the correct classloader. if(callerCL == null) { callerCL = Thread.currentThread().getContextClassLoader(); } } if(url == null) { throw new SQLException("The url cannot be null", "08001");} println("DriverManager.getConnection("" + url + "")"); if (!initialized) { initialize();}synchronized (DriverManager.class){ // use the readcopy of drivers drivers = readDrivers; }// Walk through the loaded drivers attempting to make a connection.// Remember the first exception that gets raised so we can reraise it.SQLException reason = null;for (int i = 0; i < drivers.size(); i++) { DriverInfo di = (DriverInfo)drivers.elementAt(i); // If the caller does not have permission to load the driver then // skip it. if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {println(" skipping: " + di);continue; } try {println(" trying " + di); //在注册的驱动中得到相应的连接Connection result = di.driver.connect(url, info);if (result != null) { // Success! println("getConnection returning " + di); return (result);} } catch (SQLException ex) {if (reason == null) { reason = ex;} }} // if we got here nobody could connect.if (reason != null) { println("getConnection failed: " + reason); throw reason;} println("getConnection: no suitable driver found for "+ url);throw new SQLException("No suitable driver found for "+ url, "08001"); }?进入com.mysql.jdbc.Driver下connect(url,info)方法NonRegisteringDriver
?
?
public java.sql.Connection connect(String url, Properties info)throws SQLException {if (url != null) {if (StringUtils.startsWithIgnoreCase(url, LOADBALANCE_URL_PREFIX)) {//负载均衡的配置return connectLoadBalanced(url, info);} else if (StringUtils.startsWithIgnoreCase(url,REPLICATION_URL_PREFIX)) {//复制return connectReplicationConnection(url, info);}}Properties props = null;if ((props = parseURL(url, info)) == null) {return null;}if (!"1".equals(props.getProperty(NUM_HOSTS_PROPERTY_KEY))) {return connectFailover(url, info);}try {//初始化链接Connection newConn = com.mysql.jdbc.ConnectionImpl.getInstance(host(props), port(props), props, database(props), url);return newConn;} catch (SQLException sqlEx) {// Don't wrap SQLExceptions, throw// them un-changed.throw sqlEx;} catch (Exception ex) {SQLException sqlEx = SQLError.createSQLException(Messages.getString("NonRegisteringDriver.17") //$NON-NLS-1$+ ex.toString()+ Messages.getString("NonRegisteringDriver.18"), //$NON-NLS-1$SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE, null);sqlEx.initCause(ex);throw sqlEx;}}??对com.mysql.jdbc.JDBC4Connection的初始化
?
protected static Connection getInstance(String hostToConnectTo,int portToConnectTo, Properties info, String databaseToConnectTo,String url) throws SQLException {if (!Util.isJdbc4()) {return new ConnectionImpl(hostToConnectTo, portToConnectTo, info,databaseToConnectTo, url);} //初始化return (Connection) Util.handleNewInstance(JDBC_4_CONNECTION_CTOR,new Object[] {hostToConnectTo, Integer.valueOf(portToConnectTo), info,databaseToConnectTo, url }, null);}?进入Jdbc4Connection的代码跟踪
?
?
protected ConnectionImpl(String hostToConnectTo, int portToConnectTo, Properties info,String databaseToConnectTo, String url)throws SQLException {this.charsetToNumBytesMap = new HashMap();this.connectionCreationTimeMillis = System.currentTimeMillis();this.pointOfOrigin = new Throwable(); if (databaseToConnectTo == null) {databaseToConnectTo = "";}// Stash away for later, used to clone this connection for Statement.cancel// and Statement.setQueryTimeout().//this.origHostToConnectTo = hostToConnectTo;this.origPortToConnectTo = portToConnectTo;this.origDatabaseToConnectTo = databaseToConnectTo;try {Blob.class.getMethod("truncate", new Class[] {Long.TYPE});this.isRunningOnJDK13 = false;} catch (NoSuchMethodException nsme) {this.isRunningOnJDK13 = true;}this.sessionCalendar = new GregorianCalendar();this.utcCalendar = new GregorianCalendar();this.utcCalendar.setTimeZone(TimeZone.getTimeZone("GMT"));this.log = LogFactory.getLogger(getLogger(), LOGGER_INSTANCE_NAME, getExceptionInterceptor());// We store this per-connection, due to static synchronization// issues in Java's built-in TimeZone class...this.defaultTimeZone = Util.getDefaultTimeZone();if ("GMT".equalsIgnoreCase(this.defaultTimeZone.getID())) {this.isClientTzUTC = true;} else {this.isClientTzUTC = false;}this.openStatements = new HashMap();if (NonRegisteringDriver.isHostPropertiesList(hostToConnectTo)) {Properties hostSpecificProps = NonRegisteringDriver.expandHostKeyValues(hostToConnectTo);Enumeration<?> propertyNames = hostSpecificProps.propertyNames();while (propertyNames.hasMoreElements()) {String propertyName = propertyNames.nextElement().toString();String propertyValue = hostSpecificProps.getProperty(propertyName);info.setProperty(propertyName, propertyValue);}} else {if (hostToConnectTo == null) {this.host = "localhost";this.hostPortPair = this.host + ":" + portToConnectTo;} else {this.host = hostToConnectTo;if (hostToConnectTo.indexOf(":") == -1) {this.hostPortPair = this.host + ":" + portToConnectTo;} else {this.hostPortPair = this.host;}}}this.port = portToConnectTo;this.database = databaseToConnectTo;this.myURL = url;this.user = info.getProperty(NonRegisteringDriver.USER_PROPERTY_KEY);this.password = info.getProperty(NonRegisteringDriver.PASSWORD_PROPERTY_KEY);if ((this.user == null) || this.user.equals("")) {this.user = "";}if (this.password == null) {this.password = "";}this.props = info;initializeDriverProperties(info);try { //获取数据库的信息this.dbmd = getMetaData(false, false);initializeSafeStatementInterceptors(); //======================================创建远程IO连接createNewIO(false);unSafeStatementInterceptors();} catch (SQLException ex) {cleanup(ex);// don't clobber SQL exceptionsthrow ex;} catch (Exception ex) {cleanup(ex);StringBuffer mesg = new StringBuffer(128);if (!getParanoid()) {mesg.append("Cannot connect to MySQL server on ");mesg.append(this.host);mesg.append(":");mesg.append(this.port);mesg.append(".\n\n");mesg.append("Make sure that there is a MySQL server ");mesg.append("running on the machine/port you are trying ");mesg.append("to connect to and that the machine this software is "+ "running on ");mesg.append("is able to connect to this host/port "+ "(i.e. not firewalled). ");mesg.append("Also make sure that the server has not been started "+ "with the --skip-networking ");mesg.append("flag.\n\n");} else {mesg.append("Unable to connect to database.");}SQLException sqlEx = SQLError.createSQLException(mesg.toString(),SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE, getExceptionInterceptor());sqlEx.initCause(ex);throw sqlEx;}}??
?
?
?
?