《Java EE SSM框架》学习笔记(4)

项目路径:https://share.weiyun.com/5oetQPG

 

MyBatis配置项的顺序不能颠倒,如果颠倒了它们的顺序,则启动阶段就会发生异常,导致程序无法运行。

使用property子元素:

这样定义一次就可以到处引用了,如${database.username},但要定义的参数太多,则使用properties文件。

使用properties文件:

定义jdbc.properties文件

使用properties的属性resource来引入properties文件:

解密用户名和密码后创建SqlSessionFactory

满足运维人员对用户名和密码,保密的需求。

配置的优先级:程序传递方式 > properties文件的方式 > 使用property子元素的方式。

 

settings设置:

是MyBatis中最复杂的配置,能深刻影响MyBatis底层的运行,经常修改的一些规则:

自动映射、驼峰命名映射、级联规则、是否启动缓存、执行器类型。

配置是否启动缓存:

<settings>
    <setting name="cacheEnabled" value="true"/>
</settings>

 

typeAliases别名:

系统定义别名:

在MyBatis中别名由类TypeAliasRegistry去定义。

一般对基本类型int定义的别名为,_int;类或包装器类定义的别名为,String为string、List为list、Long为long。

通过Configuration获取TypeAliasRegistry类对象

其中的,registerAlias方法去注册别名;getTypeAliasRegistry方法获取别名。

自定义别名:

可以支持扫描别名,自动将类名的第一个字母变为小写,作为别名。

若出现冲突,则使用注解进行区分:

 

typeHandler类型转换器:

在JDBC中,需要在PreparedStatement对象中设置那些,已经预编译过的SQL语句的参数。

执行SQL后,通过ResultSet对象,获取得到数据库的数据。

在typeHandler中,分为jdbcType和javaType,typeHandler的作用使其两个类型相互转换。

系统定义的typeHandler:

一般无须显式声明jdbcType和javaType,MyBatis会自己探测。

但一般枚举类需要自己去编写规则。

在MyBatis中typeHandler都要实现接口:org.apahe.ibatis.type.TypeHandler

系统注册typeHandler:

一般自定义的typeHanlder不用代码注册,而是通过配置或扫描。

自定义typeHandler:

在xml中配置typeHandler:

启用typeHandler的方式:

要么指定了与typeHandler一致的jdbcType和javaType,要么直接指定typeHandler具体实现类。

若一些数据从数据返回为空,则采用指定与typeHandler一致的jdbcType和javaType的方法,避免系统不知采用哪个typeHandler处理,从而产生异常。

若typeHandler采用包扫描,则无法指定具体的jdbcType和javaType,可使用注解的方式配置:

 

枚举typeHandler:

绝大多数情况下,typeHandler因为枚举而使用。

MyBatis已经定义了两个类来支持,枚举类型,但一般作用不大:

EnumOrdinalTypeHandler是根据,枚举数组小标索引的方式,进行匹配的。

它要求数据库返回一个整数(可以是以varchar作为类型的整数)作为其下标,根据下标找到对应的枚举类型。

EnumTypeHandler会把使用的名称转化为对应的枚举。

如,数据库返回的字符串“MALE”,进行Enum.valueOf(SexEnum.class,"MALE");转换。

但是使用是上述两种方式,会带来很大的局限性,一般自定义枚举typeHandler。

 

文件操作:

若数据库数据类型为blog,java数据类型为byte[],则使用BlogTypeHandler。

在现实中,一次性地将大量数据加载到JVM中,会给服务器带来很大压力。

因此,一般使用文件流的形式,所以,

数据库数据类型为blog,java数据类型为InputStream,则使用BlogInputStreamTypeHandler

因为性能不佳,大型互联网的网站会采用文件服务器的形式。

 

ObjectFactory(对象工厂):

创建结果集时,会使用一个对象工厂来完成创建这个结果集实例。

一般情况,MyBatis会使用其定义的对象工厂——DefaultObjectFactory。

若要自定义对象工厂,则继承DefaultObjectFactory:

public class MyObjectFactory extends DefaultObjectFactory {

    Logger log = Logger.getLogger(MyObjectFactory.class);

    private Object temp = null;

    @Override
    public void setProperties(Properties properties) {
        super.setProperties(properties);
        log.info("初始化参数:【" + properties.toString() + "】");
    }

    //方法二
    @Override
    public <T> T create(Class<T> type) {
        T result = super.create(type);
        log.info("创建对象:" + result.toString());
        log.info("是否和上次创建的是同一个对象:【" + (temp == result) + "】");
        return result;
    }

    //方法一
    @Override
    public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
        T result = super.create(type, constructorArgTypes, constructorArgs);
        log.info("创建对象:" + result.toString());
        temp = result;
        return result;
    }

    @Override
    public <T> boolean isCollection(Class<T> type) {
        return super.isCollection(type);
    }
}

最后在配置文件对对象工厂进行配置:

运行结果是,先调用方法一,后调用方法二。

 

插件:

插件是MyBatis中最强大和灵活的组件,同时也是最复杂、最难以使用的组件,而且它十分危险。

应用它之前,一定要掌握底层的构成和运行原理。

 

environment(运行环境):

主要的作用是,配置数据库信息,可配置多个数据库。

下面又分为两个可配置的元素:事务管理器、数据源。

实际工作中,会采用Spring对数据源和数据库的事务进行管理。

transactionManager(事务管理器):

transactionManager提供了两个实现类,需要实现接口Transaction(提交、回滚、关闭等数据库事务方法)

因此也对应两个相应的工厂类,需实现TransactionFactory接口。

于是可把事务管理器配置成如下方式:

JDBC:以JDBC的方式对数据库的提交和回滚进行操作。

MANAGED:把事务交给容器处理,可对closeConnection属性设置为false,来阻止它默认关闭。

自定义事务工厂:需实现TransactionFactory接口

自定义了事务工厂,还需通过实现Transaction接口,自定义事务类,就能够通过自定义事务规则,满足需要。

 

environment数据源环境:

存在三个数据源工厂:

PooledDataSourceFactory、UnpooledDataSourceFactory、JndiDataSourceFactory。

JndiDataSourceFactory会根据JNDI的信息,拿到外部容器实现的数据库连接对象。

三个数据源工厂,最后生成的产品都会是一个实现了DataSource接口的数据库连接对象。

UNPOOLED:采用非数据库池的管理方式,每次请求都会打开一个新的数据库连接,所以创建比较慢。传递属性给数据库驱动是个可选项,且属性的前缀为“driver”。

POOLED:利用“池”的概念将JDBC的Connection对象组织起来,省去了创建新的连接实例时的初始化和认证时间。

JNDI:为了能在如EJB或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的引用。

该数据源有两个属性可配置:

initial_context:用来在InitialContext中寻找上下文,如initialContext.lookup(initial_context)。

data_source:引用数据源实例位置上下文的路径。

可通过添加前缀“env.”直接把属性传递给初始化上下文InitialContext。

MyBatis也支持第三方数据源,例如使用DBCP数据源,则需提供一个自定义DataSourceFactory:

在配置文件中,进行相应的配置:

 

databaseIdProvider数据库厂商标识:

使用系统默认的databaseIdProvider:

name是数据库名称,可通过connection.getMetaData().getDatabaseProductName()获取。

value是一个别名,可在mapper文件中,标识一条SQL语句适用于哪种数据库。

当databaseIdProvider属性被配置时,系统会优先取到和数据库配置一致的SQL,若没有databaseId的SQL,则把它当作默认值。如果还是取不到,则会抛出异常。

 

不使用系统规则:

自定义DatabaseIdProvider:

public class MyDatabaseIdProvider implements DatabaseIdProvider {

	private static final String DATEBASE_TYPE_DB2 = "DB2";
	private static final String DATEBASE_TYPE_MYSQL = "MySQL";
	private static final String DATEBASE_TYPE_ORACLE = "Oralce";

	private Logger log = Logger.getLogger(MyDatabaseIdProvider.class);

	@Override
	public void setProperties(Properties props) {
		log.info(props);
	}

	@Override
	public String getDatabaseId(DataSource dataSource) throws SQLException {
		Connection connection = dataSource.getConnection();
		String dbProductName = connection.getMetaData().getDatabaseProductName();
		if (MyDatabaseIdProvider.DATEBASE_TYPE_DB2.equals(dbProductName)) {
			return "db2";
		} else if (MyDatabaseIdProvider.DATEBASE_TYPE_MYSQL
				.equals(dbProductName)) {
			return "mysql";
		} else if (MyDatabaseIdProvider.DATEBASE_TYPE_ORACLE
				.equals(dbProductName)) {
			return "oracle";
		} else {
			return null;
		}
	}
}

setProperties方法可以读取配置的参数;getDatabaseId方法的返回值,返回去配置相应的SQL语句。

 

引入映射器的方法:

用文件路径引入:

用包名引入:

用类注册引入:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章