Mondiran creates a connection and mondiran creates a connection.
The url used to create a connection using jdbc is in the following format: jdbc: mysql: // hostname: port/database? Key1 = value1 & key2 = value2, which must start with "jabc: mysql" in the URL. The address and port of the database server, database name, and other attributes must be declared, take "? "Segmentation, each attribute is separated by" & "characters, but mondrian is different from a relational database such as OLAP Server and mysql. After all, it does not store any data, it is more like a tool (similar to hive). It can translate MDX into a series of SQL statements and then submit them to the relational database for execution, therefore, it cannot be called a server independently (in my understanding, you only need to know the IP address, port, and some other parameters for server usage ). To use the built-in DriverManager of java to create a connection, mondrian makes this compatibility. When using a database such as mysql, we will first perform the following operations:
Class. forName(driver);connection = DriverManager. getConnection(url , username ,password );
The getConnection function returns java. SQL. connection object. This Connection is a common database Connection, but mondrian creates a Connection to the OLAP engine in the same way. Its driver is mondrian. olap4j. mondrianOlap4jDriver. Its url has its own unique structure. Let's take a look at how to create a connection in mondrian. In addition to the above two parts, we also need to perform other operations:
Class. forName(driver);connection = DriverManager. getConnection(url , username ,password );OlapConnection olapConnection = connection.unwrap(OlapConnection.class);
The url format in mondrian is as follows: jdbc: mondrian: Jdbc = jdbc: mysql: // 10.241.20.157: 3306/foodmart? User = root & password = root; Catalog = C: \ Users \ Administrator \ Desktop \ nrtp \ FoodMart. xml; it can be seen that each item in the url is separated by ";", similar to mysql starting with "jdbc: mysql". The url connected by mondrian must start with "jdbc: mondrian: ", in addition to" Jdbc "and" Catalog "attribute fields, perform the following operations in the static getConnection method of DriverManager:
public static Connection getConnection(String url, String user, String password) throws SQLException { java.util.Properties info = new java.util.Properties(); if (user != null) { info.put("user", user); } if (password != null) { info.put("password", password); } return (getConnection(url, info, Reflection.getCallerClass())); }
This function is used to create all database connections. In fact, it is used to create a Properties object, add the user and password attributes, and then call other getConnection methods:
private static Connection getConnection( String url, java.util.Properties info, Class<?> caller) throws SQLException { /* * 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. */ ClassLoader callerCL = caller != null ? caller.getClassLoader() : null; 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 + "\")"); // Walk through the loaded registeredDrivers attempting to make a connection. // Remember the first exception that gets raised so we can reraise it. SQLException reason = null; for(DriverInfo aDriver : registeredDrivers) { // If the caller does not have permission to load the driver then // skip it. if(isDriverAllowed(aDriver.driver, callerCL)) { try { println(" trying " + aDriver.driver.getClass().getName()); Connection con = aDriver.driver.connect(url, info); if (con != null) { // Success! println("getConnection returning " + aDriver.driver.getClass().getName()); return (con); } } catch (SQLException ex) { if (reason == null) { reason = ex; } } } else { println(" skipping: " + aDriver.getClass().getName()); } } // 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"); }
After completing so many statements, it is actually the for statement that executes the real create connection. The classloader is set in front of the statement, because we use Class before calling getConnection. the forName function only gives a driver Class Name. reflection is required to create an object, but the registeredDrivers object is traversed in this for loop, this is a static List object of the DriverManager class, but we didn't perform any operation on the DriverManager class before calling getConnection. When did this object put data, at this time, we should take a look at the Class before executing getConnection. the forName method is used to load the specified class with the current classLoader. This class will be initialized when the class is loaded (deployment initializes any object ), including initializing some static code areas. olap4j. the MondrianOlap4jDriver class has the following static code area:
static { try { register(); } catch (SQLException e) { e.printStackTrace(); } }
Here, the register Method executes the following statement: DriverManager. registerDriver (new MondrianOlap4jDriver (); Haha, the driver is registered to DriverManager here. In the registerDriver function, DriverManager adds the registered driver object to the registeredDrivers object, in this way, the previous questions are solved, and I have been wondering about the role of this forName statement. I think this method should be used for other driver classes (including mysql and oracle. The getConnection method traverses every Member in the registeredDrivers list, and then tries to create a connection with each driver until the first driver can be created successfully. If the creation fails, the error message in reason is the failure information of the first driver to create a connection. The method for creating a connection is Connection con = aDriver. driver. connect (url, info); where info is the properties that contains the user and password information, and then go back to the MondrianOlap4jDriver class to create a connection, it can be seen from this that DriverManager is actually a factory. You need to register a driver for it when creating a connection, and use each specific driver to complete the creation of an object. The method for creating a connection in the MondrianOlap4jDriver class is as follows:
public Connection connect(String url, Properties info) throws SQLException { if (!MondrianOlap4jConnection.acceptsURL(url)) { return null; } return factory.newConnection(this, url, info); }
The factory here is a member variable of the driver, which was created during driver initialization. In mondrian, it uses different factory according to different jdbc versions, the specific policy is that different versions of jdbc contain different classes, and then use the class. forName determines whether the current version of the class exists (this policy can save some version configuration information). Currently, the factory used is "mondrian. olap4j. factoryJdbc41Impl ", this function will create and return a parent object. This object actually creates its parent class Object MondrianOlap4jConnection. Its constructor is as follows: MondrianOlap4jConnection (Factory factory Factory, MondrianOlap4jDriver driver, string url, Propert Ies info) throws SQLException parameters are the factory objects and driver objects mentioned above. The configuration information transmitted by the connection url and DriverManager. I think this object is actually used to implement a layer conversion between the olap4j interface and the real connection between the olap4j interface and mondrian. To create a connection, we mainly create a native connection of mondrian, save the server, schema, and other information related to the connection. The statement for creating a connection is as follows:
this.mondrianConnection = (RolapConnection) mondrian.olap.DriverManager .getConnection(list, null);
Mondrian is connected through the DriverManager of mondrian. The list is the configuration information of the key-value Pair and info in the resolved url. The second parameter is the CatalogLocator object, here is null, which is actually useless. The first step to create a mondrian connection is to create a specified server. In mondrian, the server is used to maintain and manage the connection, when each connection is created, the server used will be determined based on the "Instance" configuration specified in the URL (why multiple servers will be used for further research ), if this configuration is not specified, the default server is used. All the servers in mondrian are maintained by the Global Object MondrianServerRegistry. However, if the server cannot be found based on the Instance, an exception is thrown and no new server is created, the Trace call logic shows that the server is created only when the XMLA service is used. This is not discussed here. It is assumed that all URLs do not contain the Instance configuration. The entry for server creation is MondrianServerRegistry. createWithRepository, which requires two parameters: the RepositoryContentFinder object and the CatalogLocator object. The default server also uses the default two objects. The CatalogLocator object is used to process the specified Catalog information in the URL, no processing is performed by default. Create a RolapConnection object, which is the internal connection of mondrian. Its constructor is RolapConnection (MondrianServer server, Util. propertyList connectInfo, RolapSchema schema, DataSource dataSource). The parameters are the configuration information of the specified server and URL respectively. The Schema object used is null. The specified datasource information is null. Each connection is assigned a globally unique ID, which increments and then determines the Provider configuration. This configuration is either specified as mondrian in the URL or unspecified. Then extract the values configured for "Catalog", "JdbcUser", "Jdbc", and "DataSource" respectively, and create a dataSource object for the underlying data clerk Based on the URL (DataSource is an interface, the getConnection function is defined with the username and password parameter. The dataSource object is created based on the Jdbc, JdbcUser, and JdbcPassword specified in the URL, in addition, the JdbcDrivers configuration specified in the URL will be obtained to load all the drivers specified here (each driver is used and separated), and then all the default drivers will be loaded, including "mondrian. jdbcDrivers "," sun. jdbc. odbc. jdbcOdbcDriver, org. hsqldb. jdbcDriver, oracle. jdbc. oracleDriver, com. mysql. jdbc. driver "(it will be determined before loading No), and then query the jdbc connection parameters of all data sources from the URL. These parameters are specified through jdbc. xxx = yyy, where xxx is the parameter name and yyy is the parameter value. Then, you have determined whether to create a datasource pool based on the "PoolNeeded" parameter specified in the URL. By default, this pool is created for data sources created using the specified Jdbc, data sources specified by the DataSource parameter are not created. At this time, the created DataSource object is divided into four situations (Jdbc is used when both Jdbc and DataSource are specified): 1. Jdbc is specified in the mondrian connection URL and PoolNeeded is not specified: in this case, the data source object will be obtained from the pool according to the jdbc url and jdbc configuration information in the RolapConnectionPool (if it is mysql, autoReconnect = true will be added ), the PoolingDataSource type object provided in dbcp is actually returned. 2. Specify Jdbc and PoolNeeded = false in the mondrian connection URL: in this case, mondrian considers that you do not need to cache data, so a new DataSource object is created, the type is DriverManagerDataSource. Every time you call getConnection, you can use the DriverManager provided by java to create a connection. 3. Specifying DataSource In the mondrian connection URL does not specify PoolNeeded: in this case, a cached DataSource object will also be created using RolapConnectionPool. 4. Specify DataSource In the mondrian connection URL and specify PoolNeeded = true: in this case, the user name and password will be specified to determine whether to create the UserPasswordDataSource object (this is actually a proxy ), if not specified, use the default constructor of this class to create a DataSource object based on the class specified by the dataSource parameter. No matter which method is used to create DataSource, it will be saved in the connection Member of mondrian. getConnection is used to obtain the connection to the data source each time it is created. After the DataSource is created, the current mondrian connection is added to the server and saved by a map. The key is the id allocated by the connection and the value is the connection object. Next, perform different operations based on whether the schema parameter is null. If the current schema is equal to null, a statement is created and added to Locus (this is often used in mondrian, in detail later), create a Schema object, which is the key here. parse and save the information of all cubes defined in the xml file, first, the "Role" parameter in the URL will be parsed after the schema is created, and the role of the current connection will be processed. By default, the default role (ALL) of the schema will be used ). Now mondrian's connection is created. The main operation is to create the DataSource object and Schema object. The latter is created through the get interface improved by RolapSchemaPool, during creation, the system determines whether to use the schema pool based on the "UseSchemaPool" parameter. The default value is true. If false is specified, a new Schema object is created, otherwise, you need to search for the key from schemaPool based on the "JdbcConnectionUuid" parameter, url Information of the jdbc connection, dataSource parameter, and md5 value of all the contents of the read catalog. If the "UseContentChecksum" parameter is specified in the URL, based on this parameter, determine whether to use the md5 value of all contents of the catalog as the key (that is, do not use the jdbc url as part of the key ), of course, no matter which method is used to obtain the schema from the pool, the schema has an expiration time when it is added to the pool, which is specified by the "UseSchemaPool" parameter, if this parameter is not specified, it is set to-1 s ). The process of creating a schema is complex. It mainly involves loading all the content of the schema file and performing initialization operations, in addition, a mondrian connection will be created during schema Creation (in fact, it is useless). Here, the RolapConnection constructor is recursively executed (see the above ), however, at this time, the schema is no longer null. After the DataSource is created, a connection is created, and a result is returned, in addition, the InternalConnection created in the schema does not perform any other operations. Therefore, we can assume that this step is only used to test the connectivity of the data source. In addition, the Schema constructor creates the AggTableManager object and the performancechangelistener object. After the schema is created, all cubes and related information are loaded from the schema file (catalog content), which is quite complex. After creating a mondrian connection, you also need to make some additional settings for the olap4j connection, so we will discuss it later. Finally, we will summarize all the parameters in the URL for creating a connection. The parameters are separated by ';'. If 'appears in the value of a parameter '; '(for example, the jdbc password, in the url of the hive jdbc connection), you need to enclose the value in quotation marks as a complete value. All parameters are saved in the RolapConnectionProperties class, including: 1. Provider: In mondrian, its value is either not specified or specified as mondrian2. Jdbc: Specifies the jdbc url Information of the data source. 3. JdbcDrivers: Specifies the driver class of the data source. multiple data sources can be specified, separated by commas. 4. JdbcUser: User Name for connecting to the data source 5. JdbcPassword: Password for connecting to the data source 6. Catalog: schema address, which can be an http url or a local file. 7. CatalogContent: All contents of the schema, an xml file. 8. CatalogName: schema name, which is not used currently. 9. DataSource: Specifies the DataSource type. The javax. SQL. DataSource interface must be implemented. Jdbc, performance10, and PoolNeeded must be specified in the URL: Indicates whether to cache the DataSource object. 11. Role: permission information used by the current connection. 12. UseContentChecksum: whether to use the content of the schema file as the key to find the schema. 13. UseSchemaPool: Indicates whether to use the schema pool. If this parameter is specified, the previous item is used as the key for searching the schema. If this parameter is set to false, a new schema is created each time. 14. DynamicSchemaProcessor: You can specify a class to dynamically modify the schema content. 15. Locale: Specifies the local information. By default, locale16 and performancechangelistener of the system are used. You can set an implementation of mondrian. spi. dataSourceChangeListener interface class, used to determine whether the data source has changed. If the data source has changed, the cache needs to be updated. 17. Ignore: Configure whether to Ignore non-fatal errors and warnings during schema loading. 18. Instance: Specifies the server where the connection is created. If this parameter is not specified, the default server19 and JdbcConnectionUuid are used to identify the jdbc connection id, if this parameter is specified, you can use this configuration to determine whether the two jdbc connections are the same. 20. PinSchemaTimeout: The expiration time of the cache schema. If it is specified as a positive number, it indicates the expiration time of the strong reference of the cache schema. If it expires, it will be reclaimed by garbage collection, if it is set to 0, it indicates that the instance will never expire. If it is set to a negative number, it indicates that the schema is saved as a soft reference, and its absolute value is the expiration time of the soft reference, the time unit can be set to d, h, m, s, and ms. 21. jdbc.: jdbc parameter information, followed by the jdbc parameter name. The value is the parameter value.
Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.