【源码 农场】【实时拼车源码】【word插件的源码】preparedstatement 源码

时间:2024-11-28 17:20:15 编辑:合肥桶装水溯源码有什么用 来源:cuda 底层源码

1.Mybatis TypeHandler(类型处理器)转换参数到SQL和转换SQL查询结果到Java类
2.MyBatis自定义TypeHandler
3.求Java web增删改查 极简源码

preparedstatement 源码

Mybatis TypeHandler(类型处理器)转换参数到SQL和转换SQL查询结果到Java类

       TypeHandler在Mybatis中的作用

       在预处理语句(PreparedStatement)中设置参数或从结果集中取出值时,TypeHandler负责将获取的值以合适的方式设置到PreparedStatement,或转换成Java类型。通过重写TypeHandler或创建自己的TypeHandler,可以处理不支持的或非标准类型。

       在项目中,源码 农场对于只有有限个值的字段,常使用数字类型表示,如考试状态字段exam_status定义为tinyint。在代码中直接使用Integer表示时,读性和维护性较差,故定义枚举类来表示。需要实现TypeHandler以自动完成从数据库数字类型转换成枚举类的实时拼车源码过程。

       实现TypeHandler的方案如下:定义枚举类实现EnumBase接口,包含codeOf静态方法进行数字转换。然后创建TypeHandler类实现org.apache.ibatis.type.TypeHandler接口,重写相应方法。避免在xml配置文件为每个枚举单独声明TypeHandler,使用Java代码动态注册,word插件的源码关键在于配置类。

       Mybatis注册工厂TypeHandlerRegistry初始化常见类型转换器,如String类型。执行转换时,通过TypeHandlerRegistry获取TypeHandler。自定义枚举类能起作用,长春建站模板源码依据TypeHandlerRegistry获取TypeHandler的顺序。Mybatis使用TypeHandler实现参数设置到SQL和转换SQL查询结果到Java类的过程。

       在mapper文件中,所有parameter入参的Java参数关联TypeHandler,解析成ParameterMapping对象,其中每条SQL的flink滑动窗口源码parameter入参关联UnknownTypeHandler,因为字段未指定JavaType和jdbcType属性,只有指定parameterType属性,Mybatis才能获取实际Java类型。resultMap的Java参数也关联TypeHandler,通过type属性获取实际Java类型并关联TypeHandler。

       执行代码时,SQL参数设置和查询结果转换到Java类的过程由TypeHandler完成。对于参数设置,调用TypeHandler设置SQL参数,获取真正TypeHandler是通过TypeHandlerRegistry.getTypeHandler方法实现。转换查询结果到Java类的过程复杂,由DefaultResultSetHandler处理。

       了解Mybatis执行流程有助于深入理解TypeHandler的作用和实现细节。建议实际项目中实践TypeHandler的使用,提高代码的可读性和可维护性。

       TypeHandler源码地址:[提供源码GitHub链接]

MyBatis自定义TypeHandler

       MyBatis自定义TypeHandler1什么是TypeHandler

       TypeHandler根据字面意思即为类型处理器

       引用官方文档的描述:MyBatis在设置预处理语句(PreparedStatement)中的参数或从结果集中取出一个值时,都会用类型处理器将获取到的值以合适的方式转换成Java类型

       MyBatis存在一些默认的类型处理器,可参考官方文档

2为什么要使用TypeHandler

       在开发过程中,当默认的TypeHandler无法满足需求时,例如遇到MyBatis不支持的数据类型或需要特殊处理的类型转换,便需要自己定制对应的TypeHandler

       笔者会在下面的代码实现中完成如下几种情况的TypeHandler:

       逗号分隔保存在数据库中的数据,在对应的Java类中为数组

       自定义枚举

3如何自定义TypeHandler

       MyBatis提供了接口org.apache.ibatis.type.TypeHandler和类org.apache.ibatis.type.BaseTypeHandler

       官方文档给出的示例为继承BaseTypeHandler,笔者在这里也使用这种方式

       先来观察一下官方的StringTypeHandler:

publicclassStringTypeHandlerextendsBaseTypeHandler<String>{ @OverridepublicvoidsetNonNullParameter(PreparedStatementps,inti,Stringparameter,JdbcTypejdbcType)throwsSQLException{ ps.setString(i,parameter);}@OverridepublicStringgetNullableResult(ResultSetrs,StringcolumnName)throwsSQLException{ returnrs.getString(columnName);}@OverridepublicStringgetNullableResult(ResultSetrs,intcolumnIndex)throwsSQLException{ returnrs.getString(columnIndex);}@OverridepublicStringgetNullableResult(CallableStatementcs,intcolumnIndex)throwsSQLException{ returncs.getString(columnIndex);}}

       方法名称和代码都简洁明了,观察可知,只需要完成四个方法的覆盖,即可实现自定义TypeHandler

3.1逗号分隔字符串转数组

       假设用户表t_user设计如下:

idusernametags1adminadmin,user

       对应的Java类为:

@Data@NoArgsConstructor@SuperBuilder(toBuilder=true)publicclassUser{ privateStringid;privateStringusername;privateString[]tags;}

       tags属性在数据库中用逗号分隔的字符串保存,但User类对应的属性为String数组

       可以创建StringArrayTypeHandler来解决类型转换的问题:

publicclassStringArrayTypeHandlerextendsBaseTypeHandler<String[]>{ @OverridepublicvoidsetNonNullParameter(PreparedStatementpreparedStatement,inti,String[]strings,JdbcTypejdbcType)throwsSQLException{ preparedStatement.setString(i,StringUtils.join(strings,","));}@OverridepublicString[]getNullableResult(ResultSetresultSet,Strings)throwsSQLException{ returnconvert(resultSet.getString(s));}@OverridepublicString[]getNullableResult(ResultSetresultSet,inti)throwsSQLException{ returnconvert(resultSet.getString(i));}@OverridepublicString[]getNullableResult(CallableStatementcallableStatement,inti)throwsSQLException{ returnconvert(callableStatement.getString(i));}/***将查询值转换为数组**@paramvalue查询值,String*@return转换结果,String[]*/privateString[]convert(Stringvalue){ returnStringUtils.isEmpty(value)?newString[0]:value.split(",");}}3.2自定义枚举

       如何创建包含中文名称的枚举,可以参考MyBatis中使用Java类与枚举

       先创建工具类用于根据code获取枚举实体:

publicclassValueNameEnumUtils{ privateValueNameEnumUtils(){ }publicstatic<EextendsValueNameEnum>EvalueOf(Class<E>enumClass,intvalue){ E[]enumConstants=enumClass.getEnumConstants();for(Ee:enumConstants){ if(e.getValue()==value){ returne;}}returnnull;}}

       和3.1中的情况不同,枚举的具体类型是不确定,所以我们要使用泛型的方式处理TypeHandler

       创建ValueNameEnumTypeHandler:

publicclassValueNameEnumTypeHandler<EextendsValueNameEnum>extendsBaseTypeHandler<ValueNameEnum>{ privatefinalClass<E>type;publicValueNameEnumTypeHandler(Class<E>type){ if(type==null){ thrownewIllegalArgumentException("Typeargumentcannotbenull");}this.type=type;}}

       泛型虽然名之为泛,但在编译过程中实际会发生类型擦除

       总之,对于泛型TypeHandler,我们需要声明一个用来标识具体类型的属性privatefinalClass<E>type和创建对应的构造函数publicValueNameEnumTypeHandler(Class<E>type)

       接下来和3.1中的一致,重写四个方法:

publicclassValueNameEnumTypeHandler<EextendsValueNameEnum>extendsBaseTypeHandler<ValueNameEnum>{ privatefinalClass<E>type;publicValueNameEnumTypeHandler(Class<E>type){ if(type==null){ thrownewIllegalArgumentException("Typeargumentcannotbenull");}this.type=type;}@OverridepublicvoidsetNonNullParameter(PreparedStatementps,inti,ValueNameEnumparameter,JdbcTypejdbcType)throwsSQLException{ ps.setInt(i,parameter.getValue());}@OverridepublicEgetNullableResult(ResultSetrs,StringcolumnName)throwsSQLException{ intcode=rs.getInt(columnName);returnrs.wasNull()?null:valueOf(code);}@OverridepublicEgetNullableResult(ResultSetrs,intcolumnIndex)throwsSQLException{ intcode=rs.getInt(columnIndex);returnrs.wasNull()?null:valueOf(code);}@OverridepublicEgetNullableResult(CallableStatementcs,intcolumnIndex)throwsSQLException{ intcode=cs.getInt(columnIndex);returncs.wasNull()?null:valueOf(code);}/***根据枚举值返回枚举示例**@paramcode枚举值*@return枚举实例*/privateEvalueOf(intcode){ try{ returnValueNameEnumUtils.valueOf(type,code);}catch(Exceptionex){ thrownewIllegalArgumentException("Cannotconvert"+code+"to"+type.getSimpleName()+"bycodevalue.",ex);}}}

       完成上述代码直接启动,会抛出异常:Unabletofindausableconstructorforclasscn.houtaroy.springboot.common.MyBatis.handler.ValueNameEnumTypeHandler

       产生异常的源码如下:

public<T>TypeHandler<T>getInstance(Class<?>javaTypeClass,Class<?>typeHandlerClass){ //未指定JavaType,此处为falseif(javaTypeClass!=null){ try{ Constructor<?>c=typeHandlerClass.getConstructor(Class.class);return(TypeHandler<T>)c.newInstance(javaTypeClass);}catch(NoSuchMethodExceptionignored){ //ignored}catch(Exceptione){ thrownewTypeException("Failedinvokingconstructorforhandler"+typeHandlerClass,e);}}try{ //此处抛出异常Constructor<?>c=typeHandlerClass.getConstructor();return(TypeHandler<T>)c.newInstance();}catch(Exceptione){ thrownewTypeException("Unabletofindausableconstructorfor"+typeHandlerClass,e);}}

       报错的原因直白,没有找到ValueNameEnumTypeHandler的构造函数

       首先我们要了解下Java类构造函数的机制:如果定义了构造函数,则使用定义,否则默认生成空构造函数

       在3.1中的StringArrayTypeHandler,我们没有定义构造函数,自动生成空构造函数,typeHandlerClass.getConstructor()不会抛出异常

       但ValueNameEnumTypeHandler定义了一个构造函数ValueNameEnumTypeHandler(Class<E>type),且没有指定JavaType,typeHandlerClass.getConstructor()自然抛出异常

       解决方法有两种:

       创造空的构造函数

       指定JavaType

       笔者推荐第二种,因为第一种方式枚举类属性type会产生NPE(空指针异常),MyBatis官方也我们提供了注解@MappedTypes用于指定JavaType:

@MappedTypes(ValueNameEnum.class)publicclassValueNameEnumTypeHandler<EextendsValueNameEnum>extendsBaseTypeHandler<ValueNameEnum>{ //...}4如何使用TypeHandler

       在上一章节中,我们完成了编码实现自定义TypeHandler,但完成的TypeHandler还没办法进行使用,需要手动进行配置

       有两种配置方式:局部使用和全局使用

       以StringArrayTypeHandler举例:

4.1局部使用

       在ResultMap中使用:

<resultMapid="UserResultMap"type="cn.houtaroy.springboot.common.system.model.User"><idcolumn="id"property="id"/><resultcolumn="tags"property="tags"typeHandler="cn.houtaroy.springboot.extension.mybatis.handler.StringArrayTypeHandler"/></resultMap>

       在语句中使用:

updatet_usersettags=#{ tags,typeHandler=cn.houtaroy.springboot.extension.mybatis.handler.StringArrayTypeHandler}4.2全局使用

       使用配置文件指定handler包名:

@Data@NoArgsConstructor@SuperBuilder(toBuilder=true)publicclassUser{ privateStringid;privateStringusername;privateString[]tags;}0

       注意,此配置类型为String,只能配置一个包,推荐使用下面的方式

       手写配置类:

@Data@NoArgsConstructor@SuperBuilder(toBuilder=true)publicclassUser{ privateStringid;privateStringusername;privateString[]tags;}1

       StringArrayTypeHandler不适合全局配置,它会在全部JavaType为String[]的属性上使用

5拓展阅读

       MyBatis3官方文档中TypeHandler内容:mybatis–MyBatis3|配置

       网上搜索的在SpringBean声明周期中进行全局配置:Mybatis自定义全局TypeHander_chuobenggu的博客-CSDN博客

求Java web增删改查 极简源码

       //用户新增

        public boolean addUser(Users user){

        try {

        conn = ConnDB.getConnection();

        String sql = "insert into tb_users values(default,?,?,?,?,?,?)";

        System.out.println(sql);

        ps = conn.prepareStatement(sql);

        ps.setInt(1, user.getDepID());

        ps.setString(2, user.getUserName());

        ps.setString(3, user.getUserPwd());

        ps.setString(4, user.getUserCode());

        ps.setString(5, user.getUserSex());

        ps.setInt(6, user.getUserAge());

        if(ps.executeUpdate()==1){

        return true;

        }

        } catch (Exception e) {

        e.printStackTrace();

        } finally{ //关闭当前页打开的相关对象

        ConnDB.close(conn, ps, null);

        }

        return false;

        }

       //用户删除

        public boolean delUser(int id){

        try {

        conn = ConnDB.getConnection();

        String sql = "delete from tb_users where id = ?";

        System.out.println(sql);

        ps = conn.prepareStatement(sql);

        ps.setInt(1, id);

        if(ps.executeUpdate()==1){

        return true;

        }

        } catch (Exception e) {

        e.printStackTrace();

        } finally{ //关闭当前页打开的相关对象

        ConnDB.close(conn, ps, null);

        }

        return false;

        }

       //用户编辑

        public boolean updateUser(Users user){

        try {

        conn = ConnDB.getConnection();

        String sql = "update tb_users set depID=?,userName=?,userPwd=?,userCode=?,userSex=?,userAge=? where id=?";

        System.out.println(user.getDepID()+ user.getUserName()+user.getUserPwd()+user.getUserCode()+user.getUserSex()+user.getUserAge()+user.getId());

        ps = conn.prepareStatement(sql);

        ps.setInt(1, user.getDepID());

        ps.setString(2, user.getUserName());

        ps.setString(3, user.getUserPwd());

        ps.setString(4, user.getUserCode());

        ps.setString(5, user.getUserSex());

        ps.setInt(6, user.getUserAge());

        ps.setInt(7, user.getId());

        if(ps.executeUpdate()==1){

        return true;

        }

        } catch (Exception e) {

        e.printStackTrace();

        } finally{ //关闭当前页打开的相关对象

        ConnDB.close(conn, ps, null);

        }

        return false;

        }

       //根据id查询用户

        public Users findAllUserById(int id){

        Users u = null;

        DepDao depd = null;

        try {

        conn = ConnDB.getConnection();

        String sql = "select * from tb_users where id=?";

        System.out.println(sql);

        ps = conn.prepareStatement(sql);

        ps.setInt(1, id);

        rs = ps.executeQuery();

        if(rs.next()){

        depd = new DepDao();

        Department dep = depd.findAllDepById(rs.getInt("depID"));

        System.out.println(dep.getDepName());

        u = new Users();

        u.setId(rs.getInt("id"));

        u.setDepID(rs.getInt("depID"));

        u.setUserName(rs.getString("userName"));

        u.setUserPwd(rs.getString("userPwd"));

        u.setUserCode(rs.getString("userCode"));

        u.setUserSex(rs.getString("userSex"));

        u.setUserAge(rs.getInt("userAge"));

        u.setDep(dep);

        }

        } catch (Exception e) {

        e.printStackTrace();

        } finally{ //关闭当前页打开的相关对象

        ConnDB.close(conn, ps, rs);

        }

        return u;

        }

       这是我在dao层写的代码,都调用了ConnDB这个类,这个类完成了驱动的注册,及连接数据库的功能,代码如下:

package com.asjy.util;

       import java.sql.Connection;

       import java.sql.DriverManager;

       import java.sql.PreparedStatement;

       import java.sql.ResultSet;

       import java.sql.SQLException;

       import java.sql.Statement;

       public class ConnDB {

        private  static String url = "jdbc:mysql://localhost:/news";

        private  static String user = "root";

        private  static String pass = "root";

          //1.加载驱动

        static{

        try {

        Class.forName("com.mysql.jdbc.Driver");

        } catch (ClassNotFoundException e) {

        System.out.println("驱动加载失败");

        }

        }

          //2.建立数据库连接对象

        public static Connection getConnection() throws Exception{

        return DriverManager.getConnection(url,user,pass);

        }

        //3.关闭数据库

        public static void close(Connection conn,Statement ps,ResultSet rs){

        try {

        if(rs!=null){

        rs.close();

        rs = null;

        }

        if(ps!=null){

        ps.close();

        ps = null;

        }

        if(conn!=null){

        conn.close();

        conn = null;

        }

        } catch (SQLException e) {

        e.printStackTrace();

        }

        }

       }