MyBatis主流程分析之(三)-准备SQL语句和参数替换、执行
2016-05-16 13:00
946 查看
在 MyBatis主流程分析之(二)-打开会话和数据库操作 中我们只讲了一个主流程,没有深入了解mybatis是如何准备sql语句,如何替换参数,最后查询,新增和删除数据的。这里再补充一下,深入了解。
这里可以参考JDBC-基础
在这里PreparedStatement准备了SQL语句,根据位置设置了参数,最后调用executeUpdate。那么我们看看MyBatis是如何做到的。
在我们创建StatementHandler的实现类时候,它的基类BaseStatementHandler实现了上面的功能,见源代码
BaseStatementHandler类
在DefaultParameterHandler类中(handler.parameterize(stmt)方法中调用)
类型处理器的作用就是
- 查询时把数据库存储的值转换成java类型
- 修改是把java类型转换成数据库类型存储,处理
- 下面这个表格描述了默认的类型处理器。
-
TypeHandle的接口
BaseTypeHandler类
其中StringTypeHandler的实现
在PreparedStatementHandler的实现类中
1. 存储我们的sql语
2. 存储传入参数对象
3. 利用MetaObjec对象获取或设置2(存储传入参数对象)中的值
主要属性
- sql
parameterMappings
parameterMappings内的parameterMapping分别为UserName,UserEmail和userId对象。和参数顺序一直。
parameterObject
例如一个pojo对象,User对象类。
additionalParameters
空new HashMap
metaParameters
MetaObjec的一个变量,见下文。
MetaObject的属性及其方法
主要的方法
通过这个MetaObject对象可以很方便获取或设置originalObject对象(传入对象参数)的值。
很有趣的是mybatis获取数据配合也调用了这个类,包装的对象是PooledDataSource。
这里解释了MyBatis主流程分析之(一)-环境准备中的ObjectFactory、ObjectWrapperFactory的用法和作用。
一、JDBC方式新增数据
首先,我们看看JDBC是如何实现的,无论mybatis内部怎么实现,肯定还是调用JDBC的。这里可以参考JDBC-基础
//sql语句?的地方就是PreparedStatement后面要替换的地方 String sql = "insert into user values(?,?)"; PreparedStatement pst = conn.prepareStatement(sql); for(int i = 101;i<200;i++){ //根据位置设置值 pst.setString(1,"Tom" + i); pst.setString(2,(100+i)*10); pst.executeUpdate(); }
在这里PreparedStatement准备了SQL语句,根据位置设置了参数,最后调用executeUpdate。那么我们看看MyBatis是如何做到的。
二、mybatis的PreparedStatement的SQL语句准备
这个章节主要解释mybatis如何实现JDBC的PreparedStatement pst = conn.prepareStatement(sql);在我们创建StatementHandler的实现类时候,它的基类BaseStatementHandler实现了上面的功能,见源代码
BaseStatementHandler类
//代码有删减 public Statement prepare(Connection connection) throws SQLException { Statement statement = null; try { statement = instantiateStatement(connection);//实现的主要地方 return statement; } catch (SQLException e) { closeStatement(statement); throw e; } catch (Exception e) { closeStatement(statement); } } protected Statement instantiateStatement(Connection connection) throws SQLException { //这个boundSql,在我们创建StatementHandler的实现类的时候就已经创建。这是一个比较主要的类,我们在最后将化点时间讲解这个类。 String sql = boundSql.getSql(); if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) { ..... } else if (mappedStatement.getResultSetType() != null) { return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY); } else { //这里就是JDBC的conn.prepareStatement(sql); return connection.prepareStatement(sql); } }
三、mybatis的PreparedStatement的参数设置
这个章节主要解释了JDBC的 pst.setString(1,”Tom” + i);在DefaultParameterHandler类中(handler.parameterize(stmt)方法中调用)
public void setParameters(PreparedStatement ps) throws SQLException { ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId()); //获取所有参数 List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (parameterMappings != null) { for (int i = 0; i < parameterMappings.size(); i++) { //获取某个参数 ParameterMapping parameterMapping = parameterMappings.get(i); if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; //参数的名字,属性 String propertyName = parameterMapping.getProperty(); //先从附加的 if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { value = null; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { //typeHandlerRegistry注册了某个类的处理 value = parameterObject; } else { //默认的MetaObject 的处理,根据参数获取值,这个将和boundSql一起解释 MetaObject metaObject = configuration.newMetaObject(parameterObject); value = metaObject.getValue(propertyName); } //参数列的TypeHandler TypeHandler typeHandler = parameterMapping.getTypeHandler(); //jdbcType的处理 JdbcType jdbcType = parameterMapping.getJdbcType(); if (value == null && jdbcType == null) jdbcType = configuration.getJdbcTypeForNull(); //见下面的分析,这里实现了 JDBC的 pst.setString(1,"Tom" + i); typeHandler.setParameter(ps, i + 1, value, jdbcType); } } } }
类型处理器的作用就是
- 查询时把数据库存储的值转换成java类型
- 修改是把java类型转换成数据库类型存储,处理
- 下面这个表格描述了默认的类型处理器。
类型处理器 | Java 类型 | JDBC 类型 |
---|---|---|
BooleanTypeHandler | java.lang.Boolean, boolean | 任何兼容的布尔值 |
ByteTypeHandler | java.lang.Byte, byte | 任何兼容的数字或字节类型 |
ShortTypeHandler | java.lang.Short, short | 任何兼容的数字或短整型 |
IntegerTypeHandler | java.lang.Integer, int | 任何兼容的数字和整型 |
LongTypeHandler | java.lang.Long, long | 任何兼容的数字或长整型 |
FloatTypeHandler | java.lang.Float, float | 任何兼容的数字或单精度浮点型 |
DoubleTypeHandler | java.lang.Double, double | 任何兼容的数字或双精度浮点型 |
BigDecimalTypeHandler | java.math.BigDecimal | 任何兼容的数字或十进制小数类型 |
StringTypeHandler | java.lang.String | CHAR 和 VARCHAR 类型 |
ClobTypeHandler | java.lang.String | CLOB 和 LONGVARCHAR 类型 |
NStringTypeHandler | java.lang.String | NVARCHAR 和 NCHAR 类型 |
NClobTypeHandler | java.lang.String | NCLOB 类型 |
ByteArrayTypeHandler | byte[] | 任何兼容的字节流类型 |
BlobTypeHandler | byte[] | BLOB 和 LONGVARBINARY 类型 |
DateTypeHandler | java.util.Date | TIMESTAMP 类型 |
DateOnlyTypeHandler | java.util.Date | DATE 类型 |
TimeOnlyTypeHandler | java.util.Date | TIME 类型 |
SqlTimestampTypeHandler | java.sql.Timestamp | TIMESTAMP 类型 |
SqlDateTypeHandler | java.sql.Date | DATE 类型 |
SqlTimeTypeHandler | java.sql.Time | TIME 类型 |
ObjectTypeHandler | Any | 其他或未指定类型 |
EnumTypeHandler | Enumeration Type | VARCHAR-任何兼容的字符串类型, 作为代码存储(而不是索引) |
EnumOrdinalTypeHandler | Enumeration Type | Any compatible NUMERIC or DOUBLE, as the position is stored (not the code itself). |
TypeHandle的接口
BaseTypeHandler类
public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException { if (parameter == null) { if (jdbcType == null) { throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters."); } try { ps.setNull(i, jdbcType.TYPE_CODE); } catch (SQLException e) { throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " + "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " + "Cause: " + e, e); } } else { //调用实现类 setNonNullParameter(ps, i, parameter, jdbcType); } }
其中StringTypeHandler的实现
//设置第i的值 @Override public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, parameter); } //根据columnName获取值 @Override public String getNullableResult(ResultSet rs, String columnName) throws SQLException { return rs.getString(columnName); } //根据columnIndex获取值 @Override public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return rs.getString(columnIndex); } //返回的是CallableStatement 获取值 @Override public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return cs.getString(columnIndex); }
四、mybatis的PreparedStatement的executeUpdate
这里解释了mybatis如何实现JDBC的pst.executeUpdate();在PreparedStatementHandler的实现类中
public int update(Statement statement) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; //执行语句 ps.execute(); //获取影响的函数 int rows = ps.getUpdateCount(); Object parameterObject = boundSql.getParameterObject(); KeyGenerator keyGenerator = mappedStatement.getKeyGenerator(); keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject); return rows; }
五、BoundSql类
BoundSql的作用1. 存储我们的sql语
2. 存储传入参数对象
3. 利用MetaObjec对象获取或设置2(存储传入参数对象)中的值
public BoundSql(Configuration configuration, String sql, List<ParameterMapping> parameterMappings, Object parameterObject) { this.sql = sql; this.parameterMappings = parameterMappings; this.parameterObject = parameterObject; this.additionalParameters = new HashMap<String, Object>(); this.metaParameters = configuration.newMetaObject(additionalParameters); }
主要属性
- sql
update mybatis.user set UserName=?, UserEmail=? where userId= ?
parameterMappings
parameterMappings内的parameterMapping分别为UserName,UserEmail和userId对象。和参数顺序一直。
parameterObject
例如一个pojo对象,User对象类。
additionalParameters
空new HashMap
metaParameters
MetaObjec的一个变量,见下文。
六、MetaObject类
先看看 MetaObject、ObjectWrapper和ObjectFactory、ObjectWrapperFactory的关系。MetaObject的属性及其方法
private Object originalObject;//例如一个pojo对象,例如User对象类。 private ObjectWrapper objectWrapper;//根据参数对象的不同,在构造函数中配置 private ObjectFactory objectFactory;//Configuration中配置 private ObjectWrapperFactory objectWrapperFactory;//Configuration中配置 //构造函数,私有 private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) { this.originalObject = object; this.objectFactory = objectFactory; this.objectWrapperFactory = objectWrapperFactory; if (object instanceof ObjectWrapper) { //如果参数对象实现了ObjectWrapper this.objectWrapper = (ObjectWrapper) object; } else if (objectWrapperFactory.hasWrapperFor(object)) { //如果objectWrapperFactory已经包装了对象,对用objectWrapperFactory的getWrapperFor this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object); } else if (object instanceof Map) { //是一个Map对象,使用mybatis的MapWrapper this.objectWrapper = new MapWrapper(this, (Map) object); } else if (object instanceof Collection) { //是一个CollectionWrapper对象 this.objectWrapper = new CollectionWrapper(this, (Collection) object); } else { //其他默认使用BeanWrapper this.objectWrapper = new BeanWrapper(this, object); } } //对外公开的静态方法 public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) { if (object == null) { return SystemMetaObject.NULL_META_OBJECT; } else { return new MetaObject(object, objectFactory, objectWrapperFactory); } }
主要的方法
通过这个MetaObject对象可以很方便获取或设置originalObject对象(传入对象参数)的值。
很有趣的是mybatis获取数据配合也调用了这个类,包装的对象是PooledDataSource。
这里解释了MyBatis主流程分析之(一)-环境准备中的ObjectFactory、ObjectWrapperFactory的用法和作用。
相关文章推荐
- mysql的启动
- 嗅探、中间人sql注入、反编译--例说桌面软件安全性问题
- 数据库查询优化——Mysql索引
- 数据库查询优化——Mysql索引
- 数据库查询优化——Mysql索引
- 数据库查询优化——Mysql索引
- SQL Azure (17) SQL Azure V12 - 跨数据中心标准地域复制(Standard Geo-Replication)
- jdbc的增删查改(mysql)
- mysql 备份
- 监听日志太大,有10g怎么破?
- 安装oracle和plsql
- Oracle定时值执行存储过程
- Jfinal数据库操作API总结
- 关于mongodb '$in' 查询无序问题
- Oracle 11g安装图文攻略
- linux系统上面安装redis 3.2
- PL/SQL学习
- 【MySql性能优化二】利用explain进行查询和分析sql语句
- 数据库连接池C3P0学习
- MySQL数据类型总结