MyBatis补充动态sql与逆向工程与模拟

1 动态sql

mybatis最大的特点:在mapper映射文件中 通过mybatis的sql标签来拼凑sql语句

1.1 if标签

<!-- List<Student>  getAll2(Student s); -->
<!-- 如果性别有值 性别是条件  如果党员有值  党员是条件 如果stid有值  stid是条件 -->
<select id="getAll2" resultType="Student">
    select * from student where 1=1 
    <if test="sex != null">
        and sex=#{sex}
    </if>
    <if test="sdy != null">
        and sdy=#{sdy}
    </if>
    <if test="stid != null">
        and stid=#{stid}
    </if>
</select>
<!-- List<Student>  getAll3(Student s); -->
<!--如果参数分数合理  把参数分数作为最低分来查-->
<select id="getAll3" resultType="Student">
    select * from student where 1=1 
    <if test="score != null and score gte 0 and score lte 100">
        and score >=#{score}
    </if>
</select>

<!-- List<Student>  getAll4(Integer stid,String sex,Boolean sdy); -->
<!-- 多个参数时:动态sql标签的条件中用:对象的属性名来获取属性值 -->
<!-- 多个参数时:动态sql标签的条件中用:paramx来获取参数的值:x从1开始-->
<select id="getAll4" resultType="Student">
    select * from student where 1=1 
    <if test="param1 neq null">
        and stid = #{0}
    </if>
    <if test="param2 neq null">
        and sex = #{1}
    </if>
    <if test="param3 neq null">
        and sdy = #{2}
    </if>
</select>
  • 注意1:sql的动态标签的条件中可以使用的运算符
     <!-- 
        "," ...
	    "=" ...
	    "?" ...
	    "||" ...
	    "or" ...
	    "&&" ...
	    "and" ...
	    "|" ...
	    "bor" ...
	    "^" ...
	    "xor" ...
	    "&" ...
	    "band" ...
	    "==" ...
	    "eq" ...
	    "!=" ...
	    "neq" ...
	    "<" ...
	    "lt" ...
	    ">" ...
	    "gt" ...
	    "<=" ...
	    "lte" ...
	    ">=" ...
	    "gte" ...
	    "in" ...
	    "not" ...
	    "<<" ...
	    "shl" ...
	    ">>" ...
	    "shr" ...
	    ">>>" ...
	    "ushr" ...
	    "+" ...
	    "-" ...
	    "*" ...
	    "/" ...
	    "%" ...
      -->
eq 等于
neq 不等于

gt: greater than 大于
gte: greater than or equal 大于等于

lt: less than 小于
lte: less than or equal 小于等于
  • 注意2:sql动态标签中使用字符串
<!--方式1-->
<if test="sex eq '男'.toString()   or sex eq '女'.toString() ">
		               sex=#{sex}
</if>
<!--方式2-->
<if test='sex eq "男"   or sex eq "女" '>
		               sex=#{sex}
</if>

where标签

<!-- where标签:智能判断是否加where -->
<!-- List<Student>  getAll5(Student s); -->
<select id="getAll5" resultType="Student">
    select * from student 
    <where>
        <if test="score != null and score gte 0 and score lte 100">
            score >=#{score}
        </if>
    </where>
</select>

set标签

<!-- set标签:智能判断是否清除sql片段后面的逗号:::只适用于update -->
<!-- int updateOne1(Student s); -->
<!-- 如果s中的属性有值  就更改数据库中此属性的值 -->
<update id="updateOne1" parameterType="Student">
    update student
    <set>
        <if test="sname != null">
            sname=#{sname},
        </if>
        <if test="sex eq '男'.toString()   or sex eq '女'.toString() ">
            sex=#{sex},
        </if>
        <if test="score != null and score gte 0 and score lte 100">
            score=#{score},
        </if>
        <if test="sdy != null">
            sdy=#{sdy},
        </if>
    </set>
    where sid = #{sid}
</update>

choose标签


<!-- List<Student>  getAll6(Student s); -->
<!-- 如果性别有值 把性别作为唯一条件  如果性别没值  再判断党员  如果党员没值  再判断分数 -->
<!--使用if标签实现-->
<select id="getAll6" resultType="Student">
    select * from student 
    <where>
        <if test="sex != null">
            sex = #{sex}
        </if>
        <if test="sex == null and sdy != null">
            sdy = #{sdy}
        </if>
        <if test="sex == null and sdy == null  and score != null">
            score >= #{score}
        </if>
    </where>
</select>

<!-- List<Student>  getAll7(Student s); -->
<!-- 如果性别有值 把性别作为唯一条件  如果性别没值  再判断党员  如果党员没值  再判断分数  如果分数也每值  就差stid=1作为条件 -->
<!--使用choose标签实现-->
<select id="getAll7" resultType="Student">
    select * from student 
    <where>
        <choose>
            <when test="sex != null">
                sex=#{sex}
            </when>
            <when test="sdy != null">
                sdy=#{sdy}
            </when>
            <when test="score != null">
                score  >=  #{score}
            </when>
            <otherwise>
                stid=1 
            </otherwise>
        </choose>
    </where>
</select>

trim标签

<!--trim标签: prefix:整体前面加前缀  suffix:整体后面加后缀  
                  prefixOverrides:智能判断去除片段的前缀,suffixOverrides:智能判断去除片段的后缀-->
<!--  List<Student>  getAll8(Student s); -->
<select id="getAll8" parameterType="Student"  resultType="Student">
    select * from student
    <trim prefix="where" prefixOverrides="and | or"  suffix=" and 1=1 ">
        <if test="sex != null">
            and sex=#{sex}
        </if>
        <if test="score != null">
            or score=#{score}
        </if>
        <if test="sdy != null">
            and sdy=#{sdy}
        </if>
        <if test="sname != null">
            or sname=#{sname}
        </if>
    </trim>
</select>

foreach标签

<!-- foreach标签 : 变量集合
          collection:指定集合的类型:array/list
          item: 定义变量记录集合中的元素
          index:遍历时元素的下标
          separator:每个元素之间的分隔符
          open:整体前面加的前缀
          close:整体前面加的后缀
     -->
<!-- List<Student>  getAll9(int[] ids); -->
<select id="getAll9" parameterType="int[]"  resultType="Student">
    <!-- select * from student where sid in(1,2,3,4) -->
    select * from student where sid in
    <foreach collection="array" item="id" separator="," open="(" index="i" close=")" >
        #{id}
    </foreach>
</select>


<!-- int  addSome(List<Student> list); -->
<insert id="addSome" parameterType="java.util.List">
    insert into student(sname,sage,sex,score,stid,sdy)
    <!--values (),(),(),(); -->
    <foreach collection="list"  item="stu" open="values" separator=",">
        (#{stu.sname},#{stu.sage},#{stu.sex},#{stu.score},#{stu.stid},#{stu.sdy})
    </foreach>
</insert>

bind标签

<!--bind标签:定义变量  此变量可以在sql片段中使用-->
<!-- List<Student>  getAll10(String s); -->
<select id="getAll10" resultType="Student">
    select * from student where sname like concat('%',#{sname},'%')
</select>
<!-- List<Student>  getAll11(String s); -->
<select id="getAll11" resultType="Student"  parameterType="String">
    <bind name="sn" value="'%' + _parameter + '%'"/>
    select * from student where sname like #{sn}
</select>

sql标签的条件中获取参数/参数的属性

参数是对象:通过属性名来获取参数的值

<select id="getAll3" resultType="Student" parameterType="Student">
    select * from student where 1=1 
    <if test="score != null and score gte 0 and score lte 100">
        and score >=#{score}
    </if>
</select>

参数是多个单值数据:通过paramx来获取第x个参数的值

<!-- List<Student>  getAll4(Integer stid,String sex,Boolean sdy); -->
<!-- 多个参数时:动态sql标签的条件中用:对象的属性名来获取属性值 -->
<!-- 多个参数时:动态sql标签的条件中用:paramx来获取参数的值:x从1开始-->
<select id="getAll4" resultType="Student">
    select * from student where 1=1 
    <if test="param1 neq null">
        and stid = #{0}
    </if>
    <if test="param2 neq null">
        and sex = #{1}
    </if>
    <if test="param3 neq null">
        and sdy = #{2}
    </if>
</select>

参数是一个单值数据:通过_parameter获取此唯一的参数数据

<select id="getAll12" resultType="Student"  parameterType="float">
    select * from student 
    <where>
        <if test="_parameter != null and _parameter gte 0 and _parameter lte 100">
            score >= #{score}
        </if>
    </where>
</select>

2 反向工程

2.1 概念

通过程序:由表(关系模型)直接生成实体类(域模型)及其相关代码
        由实体类自动生成表及其关系

2.2 操作

  • 创建项目
专门有一个项目 用于测试和方向工程
  • 导入jar包
jdbc
mybatis
log4j
mybatis-generator-core-1.3.2.jar
  • 创建反向工程的配置文件:generatorConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" >  
<generatorConfiguration>   
    <!-- 一个数据库一个context -->  
    <context id="infoGuardian">  
        <!-- 注释 -->  
        <commentGenerator >  
            <property name="suppressAllComments" value="true"/><!-- 生成代码的时候是否生成注释,true是取消注释,false会生成注释 -->  
            <property name="suppressDate" value="true" /> <!-- 是否生成注释代时间戳-->  
        </commentGenerator>  
          
        <!-- jdbc连接 -->  
        <jdbcConnection 
            driverClass="com.mysql.jdbc.Driver"  
            connectionURL="jdbc:mysql://localhost:3306/db_11" 
            userId="root"  
            password="root" />  
          
        <!-- 类型转换 -->  
        <javaTypeResolver>  
            <!-- 默认为false,可以把数据库中的decimal以及numeric类型解析为Integer,为true时会解析为java.math.BigDecimal) -->  
            <property name="forceBigDecimals" value="false"/>  
        </javaTypeResolver>  
          
        <!-- 生成实体类地址 -->    
        <javaModelGenerator targetPackage="com.zhiyou100.entity"  
            targetProject=".\src" >  
            <!-- 是否在当前路径下新加一层schema,
如果为fase路径com.shop.pojo, 为true:com.shop.pojo.[schemaName]  这个情况主要是oracle中有,mysql中没有schema -->  
            <property name="enableSubPackages" value="false"/>  
            <!-- 是否针对string类型的字段在set的时候进行trim调用 -->  
            <property name="trimStrings" value="true"/>  
        </javaModelGenerator>  
          
        <!-- 生成mapxml文件 -->  
        <sqlMapGenerator targetPackage="com.zhiyou100.mapper"  
            targetProject=".\src" >  
            <!-- 是否在当前路径下新加一层schema,
如果为fase路径com.shop.dao.mapper, 为true:com.shop.dao.mapper.[schemaName]  这个情况主要是oracle中有,mysql中没有schema -->  
            <property name="enableSubPackages" value="false" />  
        </sqlMapGenerator>  
          
        <!-- 生成mapxml对应client,也就是接口dao -->      
        <javaClientGenerator targetPackage="com.zhiyou100.dao"  
            targetProject=".\src" type="XMLMAPPER" >  
            <!-- 是否在当前路径下新加一层schema,
如果为fase路径com.shop.dao.mapper, 为true:com.shop.dao.mapper.[schemaName]  这个情况主要是oracle中有,mysql中没有schema -->  
            <property name="enableSubPackages" value="false" />  
        </javaClientGenerator>  
          
        <!-- 配置表信息 -->      
        <table schema="" tableName="student"  
            domainObjectName="Student" enableCountByExample="false"  
            enableDeleteByExample="false" enableSelectByExample="false"  
            enableUpdateByExample="false">  
            <!-- schema即为数据库名 tableName为对应的数据库表, domainObjectName是要生成的实体类的名字, enable*ByExample指的是否生成 对应的example类,Mybatis Generator默认设置会生成一大堆罗哩罗嗦的Example类,主要是用各种不同的条件来操作数据库,大部分是用不到的,用到的时候手工修改mapper和接口文件就行了   -->  
              
            <!-- 忽略列,不生成bean 字段 -->  
            <ignoreColumn column="stid" />  
            <!-- 指定列的java数据类型
            <columnOverride column="LONG_VARCHAR_FIELD" jdbcType="VARCHAR" /> 
              -->  
        </table>  
  
    </context>  
</generatorConfiguration>  
  • 创建启动类
public static void main(String[] args)throws Exception {
    List<String> warnings = new ArrayList<String>();
    boolean overwrite = true;
    File configFile = new File("src/generatorConfig.xml"); 
    ConfigurationParser cp = new ConfigurationParser(warnings);
    Configuration config = cp.parseConfiguration(configFile);
    DefaultShellCallback callback = new DefaultShellCallback(overwrite); 
    MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings); 
    myBatisGenerator.generate(null);
}

3 缓存

概念

当对数据库进行查询时  如果两次的sql语句一致 不再重复去服务数据库  直接使用上一次的查询结果
作用:提高程序效率+降低数据库服务器的压力

一级缓存

Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlSession而言。
所以在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。
  • 一级缓存默认是开启的

  • 一级缓存针对于同一个sqSession

  • 一级缓存使用前提:缓存不能刷新

sql映射文件

<select id="getOne1" parameterType="int"  resultType="Student">
    select * from student where sid = #{sid}
</select>
<select id="getOne2" parameterType="int"  resultType="Student">
    select * from student where sid = #{sid}
</select>

<!--  List<Student>  getAll1();-->
<select id="getAll1"  resultType="Student">
    select * from student
</select>
<!-- List<Student>  getAll2ByScore(Float score); -->
<select id="getAll2ByScore"  resultType="Student">
    select * from student where score >=#{score}
</select>

测试代码

		        //1 获取sqlsessionfactorybuilder对象
				SqlSessionFactoryBuilder  builder=new SqlSessionFactoryBuilder();
				//2 sqlsessionfactorybuilder读取核心配置文件 获取sqlsessionfactory对象
				File file=new File("src/mybatis_conf.xml");
				SqlSessionFactory factory=builder.build(new FileInputStream(file));
				//3 获取sqlsession:类似于connection连接
				SqlSession session=factory.openSession(true);//boolean参数表示是否支持事务自动提交
                StudentMapper  studentMapper=session.getMapper(StudentMapper.class);
                
                Student s1=studentMapper.getOne1(141);
                System.out.println("s1="+s1);
//                //session.clearCache();              //不使用缓存:1 刷新缓存
//                session.close();
//                session=factory.openSession(true);   //不使用缓存:2 session关闭
//                studentMapper=session.getMapper(StudentMapper.class);
//                                                     //不使用缓存:3 期间执行了dml:dml会自动刷新缓存
                System.out.println("删除::"+studentMapper.deleteByPrimaryKey(1));
                Student s2=studentMapper.getOne1(141);
                System.out.println("s2="+s2);
                
                //System.out.println(studentMapper.getAll1());
                //System.out.println(studentMapper.getAll1());
                
//                System.out.println(studentMapper.getAll2ByScore(11f));
//                System.out.println(studentMapper.getAll2ByScore(11f));
                  //使用缓存前提:  1 必须是同一个session
                  //            2 必须调用的是同一个标签
                  //            3 参数值必须相同
                  //            4 缓存不能刷新
                  //            5 期间不能执行dml
				session.close();
  • 一级缓存的生命周期
1、一级缓存的生命周期有多长?

a、MyBatis在开启一个数据库会话时,会 创建一个新的SqlSession对象,SqlSession对象中会有一个新的Executor对象。Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。

b、如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用。

c、如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用。

d、SqlSession中执行了任何一个update操作(update()、delete()、insert()) ,都会清空PerpetualCache对象的数据,但是该对象可以继续使用

二级缓存

二级缓存是application级别的缓存/SqlSessionFactory级别的缓存
mybatis的二级缓存默认是关闭的  

配置二级缓存

  • 实体类实现序列化接口
二级缓存的数据会存储在硬盘上
  • 在使用缓存的mapper映射文件中添加配置
<!--开启本mapper的namespace下的二级缓存-->
<!--
        eviction:代表的是缓存回收策略,目前MyBatis提供以下策略。
        (1) LRU,最近最少使用的,一处最长时间不用的对象
        (2) FIFO,先进先出,按对象进入缓存的顺序来移除他们
        (3) SOFT,软引用,移除基于垃圾回收器状态和软引用规则的对象
        (4) WEAK,弱引用,更积极的移除基于垃圾收集器状态和弱引用规则的对象。这里采用的是LRU,
                移除最长时间不用的对形象

        flushInterval:刷新间隔时间,单位为毫秒,这里配置的是100秒刷新,如果你不配置它,那么当
        SQL被执行的时候才会去刷新缓存。

        size:引用数目,一个正整数,代表缓存最多可以存储多少个对象,不宜设置过大。设置过大会导致内存溢出。
        这里配置的是1024个对象

        readOnly:只读,意味着缓存数据只能读取而不能修改,这样设置的好处是我们可以快速读取缓存,缺点是我们没有
        办法修改缓存,他的默认值是false,不允许我们修改
    -->
<cache eviction="LRU" flushInterval="100000" readOnly="true" size="1024"/>
  • 在使用缓存的mapper映射文件的sql标签中添加配置:(默认是true:可以不用配置)
<!--  List<Student>  getAll1();-->
<!--可以通过设置useCache来规定这个sql是否开启缓存,ture是开启,false是关闭-->
<select id="getAll1"  resultType="Student" useCache="true">
    select * from student
</select>
<!--可以通过设置useCache来规定这个sql是否开启缓存,ture是开启,false是关闭-->
<select id="getAll2"  resultType="Student" useCache="false">
    select * from student
</select>
  • 在核心配置文件中添加配置
 <settings>
       ....
       <!--这个配置使全局的映射器(二级缓存)启用或禁用缓存-->
       <setting name="cacheEnabled" value="true" />
   </settings>
  • 测试
//1 获取sqlsessionfactorybuilder对象
SqlSessionFactoryBuilder  builder=new SqlSessionFactoryBuilder();
//2 sqlsessionfactorybuilder读取核心配置文件 获取sqlsessionfactory对象
File file=new File("src/mybatis_conf.xml");
SqlSessionFactory factory=builder.build(new FileInputStream(file));
//3 获取sqlsession:类似于connection连接
SqlSession session=factory.openSession(true);//boolean参数表示是否支持事务自动提交
StudentMapper  studentMapper=session.getMapper(StudentMapper.class);
studentMapper.getAll1(); 
//studentMapper.deleteOne(1);//执行dml:刷新1级缓存 也刷新2级缓存
//session.close();
//session=factory.openSession(true);//boolean参数表示是否支持事务自动提交
//session.clearCache();//执行clear:刷新1级缓存 也刷新2级缓存
session.close();
factory=builder.build(new FileInputStream(file));//二级缓存不能夸sqlsessionfactory
session=factory.openSession(true);
studentMapper=session.getMapper(StudentMapper.class);
studentMapper.getAll1();
session.close();

4 模拟mybatis

默认原始dao方式

通过sqlsession的selectOne、selectList、delete、insert、update等方法 关联sql标签的id和参数来执行sql语句

涉及的技术:xml+反射

4.1 已有配置

实体类 Student.java

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student   implements Serializable{
    private Integer sid;

    private String sname;

    private String sex;

    private Float score;

    private Integer sage;

    private Boolean sdy;
}

配置文件 mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="/" >
    
   <select id="getAll"  resultType="com.zhiyou100.entity.Student">
       select * from student
  </select>
  
   <select id="getOneBySid"  resultType="com.zhiyou100.entity.Student" parameterType="int">
       select * from student where sid=#{sid}
  </select>
  
  <select id="getAll2ByScore"  resultType="com.zhiyou100.entity.Student" parameterType="float">
       select * from student where score >=#{score}
  </select>
  
  <delete id="deleteOne" parameterType="int">
       delete from student where sid=#{sid}
  </delete>
  
  <update id="updateOne"  parameterType="com.zhiyou100.entity.Student">
       update student set sname=#{sname},sage=#{sage},sex=#{sex},sdy=#{sdy},score=#{score} where sid=#{sid}
  </update>
  
  <insert id="addOne" parameterType="com.zhiyou100.entity.Student">
       insert into student(sname,sex,sage,sdy,score) values(#{sname},#{sex},#{sage},#{sdy},#{score});
  </insert>
</mapper>

核心配置 mybatis_conf.xml

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
	<environment id="e1">
		<dataSource type="POOLED">
			<property name="driver" value="com.mysql.jdbc.Driver" />
			<property name="url" value="jdbc:mysql://localhost:3306/db_11" />
			<property name="username" value="root" />
			<property name="password" value="root" />
		</dataSource>
	</environment>
	<mappers>
		<mapper resource="com.zhiyou100.mapper.StudentMapper.xml" />
	</mappers>
</configuration>

4.2 准备完毕开始模拟

工具类 MyUtil

  • MyUtil.java
public class MyUtil {
	/* 由xml获取document对象 */
	public static Document xml2Doc(File file) {
		try {
			// 获取文档解析器工厂对象
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			// 获取文档解析器对象
			DocumentBuilder builder = factory.newDocumentBuilder();// 实例工厂模式:
			// 通过解析器对象的parse 由xml获document对象
			return builder.parse(file);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
    /* 判断是否是基本类型或包装类型 */
	public static boolean pdBasicTypeOrString(Object obj){
		Class cla=obj.getClass();
		if(cla.isPrimitive()){
			return true;
		}
		return cla==String.class||
			   cla==Byte.class||
			   cla==Short.class||
			   cla==Integer.class||
			   cla==Long.class||
			   cla==double.class||
			   cla==Float.class||
			   cla==Boolean.class||
		       cla==Character.class;
	}
	public static void main(String[] args) {
		System.out.println(Integer.class.isPrimitive());
	}
}

配置文件实体类

  • MySqlElementEntity.java
/*获取mapper配置的全部参数*/
public class MySqlElementEntity   {
	  private String nodeName;//select update insert delete 标签
	  private String nodeId;//id 方法名
	  private String resultType;//返回类型
	  private String parameterType;//参数类型
	  private String sqlMybatis;//mybatis的sql语句 占位符为#{}
	
	public String getNodeName() {
		return nodeName;
	}
	public void setNodeName(String nodeName) {
		this.nodeName = nodeName;
	}
	public String getNodeId() {
		return nodeId;
	}
	public void setNodeId(String nodeId) {
		this.nodeId = nodeId;
	}
	public String getResultType() {
		return resultType;
	}
	public void setResultType(String resultType) {
		this.resultType = resultType;
	}
	public String getParameterType() {
		return parameterType;
	}
	public void setParameterType(String parameterType) {
		this.parameterType = parameterType;
	}
	public String getSqlMybatis() {
		return sqlMybatis;
	}
	public void setSqlMybatis(String sqlMybatis) {
		this.sqlMybatis = sqlMybatis;
	}
	public String getSqlJdbc() {
		return sqlMybatis.replaceAll("\\#\\{[a-zA-Z0-9]+\\}", "?");
	}
	
	/* 获取sql语句参数 */
	public List<String> getParameterName() {
		List<String> parameterName=new ArrayList<>();
		int startIndex=0;
		while(true){
			int index1=sqlMybatis.indexOf('{',startIndex);
			if(index1==-1){
				break;
			}
			int index2=sqlMybatis.indexOf("}",startIndex);
			parameterName.add(sqlMybatis.substring(index1+1, index2));
			if(index2==sqlMybatis.length()-1){
				break;
			}
			startIndex=index2+1;
		}
		return parameterName;
	}

	@Override
	public String toString() {
		return "MySqlElementEntity [nodeName=" + nodeName + ", nodeId=" + nodeId + ", resultType=" + resultType
				+ ", parameterType=" + parameterType + ", sqlMybatis=" + sqlMybatis + ", sqlJdbc=" + getSqlJdbc()
				+ ", parameterName=" + getParameterName() + "]";
	}
	  
	/* 测试 */
	public static void main(String[] args) {
		String sql1="update student set sname=#{sname},sage=#{sage},sex=#{sex} where sid=#{sid}";
		List<String> parameterName=new ArrayList<>();
		int startIndex=0;
		while(true){
			int index1=sql1.indexOf('{',startIndex);
			if(index1==-1){
				break;
			}
			int index2=sql1.indexOf("}",startIndex);
			parameterName.add(sql1.substring(index1+1, index2));
			if(index2==sql1.length()-1){
				break;
			}
			startIndex=index2+1;
		}
		System.out.println(parameterName);
	}
}

读取两个配置获取参数

  • MySqlSessionFactroy.java
public class MySqlSessionFactroy {
	private static String driverClass,userName,userPwd,url;//jdbc的参数
	public static Map<String, MySqlElementEntity>  sqlEntityMap;
	//String为mapper配置的id,MySqlElementEntity为内的所有参数
	
	/*构造方法 直接 初始化*/
	public MySqlSessionFactroy(File file){
		init(file);
	}
	
	/* 获取一个MySqlSession  并关联一个connection对象 获取连接*/
	public MySqlSession  openSession(){
		Connection con=null;
		try {
			con=DriverManager.getConnection(url, userName,userPwd);
		} catch (Exception e) {
			throw new RuntimeException(e);//异常转换
		}
		MySqlSession session=new MySqlSession();
		session.setCon(con);
		return session;
	}
	
	/* 初始化获取参数 与 mapper */
	private void init(File file){
		  //读取连接数据库的四大参数 获取连接
//			<environment id="e1">
//				<dataSource type="POOLED">
//					<property name="driver" value="com.mysql.jdbc.Driver" />
//					<property name="url" value="jdbc:mysql://localhost:3306/db_11" />
//					<property name="username" value="root" />
//					<property name="password" value="root" />
//				</dataSource>
//			</environment>
		    Map<String, String> jdbcMap=new HashMap<>();
		   Document docCore=MyUtil.xml2Doc(file);
		   Element dataSourceElement=(Element)docCore.getElementsByTagName("dataSource").item(0);
		   //获取器所有的property子标签
		   NodeList proList=dataSourceElement.getElementsByTagName("property");
		   for (int i = 0; i < proList.getLength(); i++) {
			      Element ele=(Element)proList.item(i);
			      jdbcMap.put(ele.getAttribute("name"), ele.getAttribute("value"));
	       }
		   driverClass=jdbcMap.get("driver");
		   userName=jdbcMap.get("username");
		   userPwd=jdbcMap.get("password");
		   url=jdbcMap.get("url");
		   //注册驱动:
		    try {
				Class.forName(driverClass);
			} catch (ClassNotFoundException e) {
				throw new RuntimeException(e);//异常转换
			}
		   //读取配置文件:<mapper resource="com.zhiyou100.mapper.StudentMapper.xml" />
		    Element mapperEle=(Element)docCore.getElementsByTagName("mapper").item(0);
		    String resource=mapperEle.getAttribute("resource");
		    resource=resource.replace(".", "/");//把所有的.转换为/
		    resource=resource.substring(0, resource.lastIndexOf('/'))+".xml";
		    resource="src/"+resource;
			Document mapperDoc=MyUtil.xml2Doc(new File(resource));
		    sqlEntityMap=new HashMap<String, MySqlElementEntity>();
		     //读取sql映射文件中sql标签
		     Element root=(Element)mapperDoc.getElementsByTagName("mapper").item(0);
		     NodeList childNodes=root.getChildNodes();
		     for (int i = 0; i < childNodes.getLength(); i++) {
				  if(childNodes.item(i) instanceof Element){
					    Element eleSql=(Element)childNodes.item(i);
					    //把每个sql标签封装为MySqlElementEntity.java对象
					    MySqlElementEntity sqlEntity=new MySqlElementEntity();
					    sqlEntity.setNodeId(eleSql.getAttribute("id").trim());
					    sqlEntity.setNodeName(eleSql.getNodeName());
					    sqlEntity.setParameterType(eleSql.getAttribute("parameterType").trim());
					    sqlEntity.setResultType(eleSql.getAttribute("resultType").trim());
					    sqlEntity.setSqlMybatis(eleSql.getTextContent().trim());
					    sqlEntityMap.put(eleSql.getAttribute("id").trim(), sqlEntity);
				  }
			}
	}
	
	/*测试*/
	public static void main(String[] args) {
		MySqlSessionFactroy factroy=new MySqlSessionFactroy(new File("src/mybatis_conf.xml"));
		System.out.println(factroy.driverClass+":"+factroy.url+":"+factroy.userName+":"+factroy.userPwd);
		System.out.println(factroy.sqlEntityMap);
	}
}

执行方法

MySqlSession.java

public class MySqlSession {
	 private Connection con;
	 
	 /*获取链接*/
     public void setCon(Connection con) {
		this.con = con;
	 }
     
	//提供五个方法
	 public Object selectOne(String id,Object...args){
		  List<Object> list=(List<Object>)execute("select", id, args);
		  return list.get(0);
	 }
	 public List<Object> selectList(String id,Object...args){
		  return (List<Object>)execute("select", id, args);
	 }
	 public int delete(String id,Object...args){
		 return (Integer)execute("delete", id, args);
	}
	 public int insert(String id,Object...args){
		 return (Integer)execute("insert", id, args);
     }
	 public int update(String id,Object...args){
		 return (Integer)execute("update", id, args);
	 }
	 
	 /* 关闭链接 */
	 public void close(){
		 try {
			con.close();
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	 }
	 
	 /* 执行jdbc */
	 private Object execute(String nodeName,String id,Object...params){
		//获取参数id对应的MySqlElementEntity对象
		 MySqlElementEntity entity=MySqlSessionFactroy.sqlEntityMap.get(id);
		 //判断是不是指定类型
		 if(!entity.getNodeName().equals(nodeName)){
			 throw new RuntimeException("必须是"+nodeName+"对应的sql标签!");
		 }
		 int hang=0;
		 List<Object>  list=null;
		 try {
			 PreparedStatement pre=null;
			 ResultSet set=null;
			
			 pre=con.prepareStatement(entity.getSqlJdbc());
			 //给占位符赋值:一个对象类型的参数:拿对象的属性给占位符赋值
			 //          一个基本数据类型+String类型的参数:直接给唯一的占位符赋值
			 //          多个类型(基本数据类型+String类型):按顺序给占位符赋值
			 if(params!=null&&params.length!=0){
				  //System.out.println(params[0]+":::MyUtil.pdBasicTypeOrString(params[0])="+MyUtil.pdBasicTypeOrString(params[0]));
				  if(params.length!=1){
					   for (int i = 0; i < params.length; i++) {
						   pre.setObject(i+1, params[i]);
					   }
				  }else if(MyUtil.pdBasicTypeOrString(params[0])){
					   pre.setObject(1, params[0]);
				  }else{
					  //说明参数是对象:拿对象的属性的值赋值给同名的占位符
					  Class claObj=params[0].getClass();
					  //获取占位符的所有名字
					  List<String> pnList=entity.getParameterName();
					  for (int i = 0; i < pnList.size(); i++) {
						    String fieldName=pnList.get(i);//拿到属性名
						    //拿到属性对象
						    Field field=claObj.getDeclaredField(fieldName);
						    field.setAccessible(true);
						    Object fieldValue=field.get(params[0]);
						    //给占位符赋值
						    pre.setObject(i+1, fieldValue);
					  }
				  }
			 }
			 //执行execute方法
			 if(nodeName.equals("select")){
				 set=pre.executeQuery();
				 //处理结果集
				 list=new ArrayList<Object>();
				 while(set.next()){
					 //把没一行封装为对象:
					 Class claResult=Class.forName(entity.getResultType());
					 Object obj=claResult.newInstance();
					 //给对象的属性封装
					 Field[] fields=claResult.getDeclaredFields();
					 for (Field field : fields) {
						  field.setAccessible(true);
						  field.set(obj, set.getObject(field.getName()));
					 }
					 list.add(obj);
				 }
			 }else{
				 hang=pre.executeUpdate();
			 }
			 if(set!=null){set.close();}
			 if(pre!=null){pre.close();}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return hang==0?list:hang;
	 }
}

4.3 测试

public class Test01 {
   public static void main(String[] args) {
	    MySqlSessionFactroy factroy=new MySqlSessionFactroy(new File("src/mybatis_conf.xml"));
	    MySqlSession session=factroy.openSession();
	    System.out.println(session.selectOne("getOne", 141));
	    System.out.println(session.selectList("getAll", null));
	    System.out.println(session.selectList("getAllByScore", 30));
	    System.out.println(session.selectList("getAllByScoreSexSdy", 30,"男",true));
	    System.out.println("添加:"+session.insert("addOne", new Student(null,"java","妖",11f,22,true)));
	    System.out.println("删除:"+session.delete("deleteOne",245));
	    System.out.println("修改:"+session.update("updateOne", new Student(234,"c++","圣",33f,55,true)));
	    session.close();
   }
}
posted @ 2021-11-05 21:12  RenVei  阅读(91)  评论(0编辑  收藏  举报