mybatis_day03

1 注解形式

1.0 注解形式和配置形式可以共存

属于的jar完全相同
  • 装备sql
DROP TABLE student;
CREATE TABLE student(
   sid INT PRIMARY KEY AUTO_INCREMENT,
   sname VARCHAR(100),
   sex CHAR(1),
   sage INT,
   sdy BOOLEAN,
   score FLOAT(4,1)
);
INSERT INTO student VALUES(
   NULL,
   SUBSTRING(REPLACE(UUID(),'-',''),1,10),
   IF(RAND()>0.5,'男','女'),
   TRUNCATE(RAND()*10+15,0),
   RAND()>0.5,
   TRUNCATE(RAND()*100,1)
   );

1.2 mapper接口

package com.zhiyou100.test04;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

public interface StudentMapper {
	public List<Student> getAll1();
	
	@Select("select * from student")
	public List<Student> getAll2();
	
	@Insert("insert into student(sname,sage,sex,sdy,score) values(#{sname},#{sage},#{sex},#{sdy},#{score})")
	public int addOne(Student s);
	
	@Delete("delete from student where sid=#{sid}")
	public int deleteOne(int sid);
	
	@Update("update student set sname=#{sname},sex=#{sex},sdy=#{sdy},score=#{score},sage=#{sage} where sid=#{sid}")
	public int updateOne(Student s);
	
	@Select("select * from student where sdy=#{0} and score <= #{1} and sex=#{2}")
	public List<Student> findSome1(boolean dy,float minScore,char sex);
	@Select("select * from student where sdy=#{sdy} and score <= #{score} and sex=#{sex}")
	public List<Student> findSome2(@Param("sdy")boolean dy,@Param("score")float minScore,@Param("sex")char sex);
}

1.3 sql配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhiyou100.test04.StudentMapper">
  <select id="getAll1" resultType="Student">
        select * from student
  </select>
</mapper>

1.4 实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain=true)
public class Student   implements Serializable{
	   private Integer sid;
	   private String sname;
	   private String sex;
	   private Integer sage;
	   private Boolean sdy;
	   private Float score;
}

2 动态sql

2.0 概念

在sql映射文件中 通过标签实现sql语句的流程控制(跳转 循环 选择)

2.1 if标签

<!--  //如果score和sex有效 就作为查询条件  如果无效就查询所有
  public List<Student> getAll2(Student s);-->
<select id="getAll2" parameterType="Student" resultType="Student">
    select * from student where 1=1 
    <!-- test属性中的score 必须是参数对象的属性名 -->
    <if test="score gte 0 and score lte 100">
        and score &gt;= #{score}
    </if>
    <!-- test属性中的sex 必须是参数对象的属性名 -->
    <if test='sex eq "男" or sex eq "女"'>
        and sex = #{sex}
    </if>
</select>

<!-- //如果sname不为null  就把sname作为条件  否则就查询所有
 public List<Student> getAll3(Student s);-->
<select id="getAll3" parameterType="Student" resultType="Student">
    select * from student where 1=1 
    <if test="sname != null">
        and sname = #{sname}
    </if>
</select>
  • 注意事项1:if标签的test属性中可以使用的运算符
     <!-- 
        "," ...
	    "=" ...
	    "?" ...
	    "||" ...
	    "or" ...
	    "&&" ...
	    "and" ...
	    "|" ...
	    "bor" ...
	    "^" ...
	    "xor" ...
	    "&" ...
	    "band" ...
	    "==" ...
	    "eq" ...
	    "!=" ...
	    "neq" ...
	    "<" ...
	    "lt" ...
	    ">" ...
	    "gt" ...
	    "<=" ...
	    "lte" ...
	    ">=" ...
	    "gte" ...
	    "in" ...
	    "not" ...
	    "<<" ...
	    "shl" ...
	    ">>" ...
	    "shr" ...
	    ">>>" ...
	    "ushr" ...
	    "+" ...
	    "-" ...
	    "*" ...
	    "/" ...
	    "%" ...
      -->
  • 注意2:在test属性中使用字符串方法:
<!--方式1-->
<if test="sex eq '男'.toString()   or sex eq '女'.toString() ">
		               sex=#{sex}
</if>
<!--方式2-->
<if test='sex eq "男"   or sex eq "女" '>
		               sex=#{sex}
</if>

2.2 where标签

智能判断是否添加where
<!-- //如果score和sex有效 就作为查询条件  如果无效就查询所有
 public List<Student> testWhere1(Student s);-->
<select id="testWhere1" parameterType="Student" resultType="Student">
    select * from student 
    <where>
        <if test="score gte 0 and score lte 100">
            and score &gt;= #{score}
        </if>
        <if test="sex eq '男'.toString() or sex eq '女'.toString()">
            and sex = #{sex}
        </if>
    </where>
</select>

2.3 set标签

只适用于update语句:智能判断是否保留sql片段后面的,
<!--  //如果属性有值就修改 没有值就保持原来的值
public int testSet01(Student s);-->
<update  id="testSet01" parameterType="Student">
    update student
    <set>  <!-- 智能判断去除sql片段后面的, -->
        <if test="sname != null">
            sname=#{sname},
        </if>
        <if test="sex != null">
            sex=#{sex},
        </if>
        <if test="score != null">
            score=#{score},
        </if>
        <if test="sage != null">
            sage=#{sage},
        </if>
        <if test="sdy != null">
            sdy=#{sdy},
        </if>
    </set> 
    where sid=#{sid}
</update>

2.4 choose标签

实现条件的多分支判断
<!-- 如果性别有值 把性别作为唯一条件  如果性别没值  再判断党员  如果党员没值  再判断年龄 如果都没值 条件是score>60-->
<!-- 使用if实现 -->
<select id="testChoose01" parameterType="Student" 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 sage != null">
            sage = #{sage}
        </if>
        <if test="sex == null and sdy == null  and sage == null">
            score &gt; 60
        </if>
    </where>
</select>
<!-- 使用choose实现 -->
<select id="testChoose02" parameterType="Student" resultType="Student">
    select * from student
    <where>
        <choose>
            <when test="sex != null ">
                sex = #{sex}
            </when>
            <when test="sdy != null ">
                sdy = #{sdy}
            </when>
            <when test="sage != null ">
                sage = #{sage}
            </when>
            <otherwise>
                score &gt; 60
            </otherwise>
        </choose>
    </where>
</select>

2.5 trim标签

<!--  //如果属性有值就修改 没有值就保持原来的值public int testTrim01(Student s);-->
<!-- trim标签的是prefix属性:整体前面加前缀 -->
<!-- trim标签的是suffix属性:整体后面加后缀 -->
<!-- trim标签的是suffixOverrides属性:智能判断每个sql片段后面的指定字符是否保留-->
<!-- trim标签的是prefixOverrides属性:智能判断每个sql片段前面的指定字符是否保留-->
<!-- trim标签的是prefix属性:整体前面加前缀 -->
<update  id="testTrim01" parameterType="Student">
    update student
    <trim prefix="set" suffix="where" suffixOverrides=",">
        <if test="sname != null">
            sname=#{sname},
        </if>
        <if test="sex != null">
            sex=#{sex},
        </if>
        <if test="score != null">
            score=#{score},
        </if>
        <if test="sage != null">
            sage=#{sage},
        </if>
        <if test="sdy != null">
            sdy=#{sdy},
        </if>
    </trim> 
    sid=#{sid}
</update>

2.6 foreach标签

<!--  //根据参数数组的所有元素的id值进行查询public List<Student> testForeach01(int[] arr);-->
<!-- select * from student where sid in(1,5,7,8,9,0) -->
<!-- foreach标签的collection属性:指定参数对象的类型::array/list -->
<!-- foreach标签的open属性:拼凑成的整个sql片段整体前面加的内容-->
<!-- foreach标签的close属性:拼凑成的整个sql片段整体后面加的内容 -->
<!-- foreach标签的item属性:为变量集合时 定义的变量来接受集合中的元素 -->
<!-- foreach标签的separator属性:每个sql片段后面智能添加的字符 -->
<!-- foreach标签的index属性:为变量集合时 定义的变量来接受元素的下标-->
<select id="testForeach01" parameterType="int[]" resultType="Student">
    select * from student where sid in 
    <foreach collection="array"  open="(" close=")"   item="id" separator=",">
        #{id}
    </foreach>
</select>

<!--  一次插入多行public int testForeach02(List<Student> list);-->
<!-- insert into student(sid,sname,sex,sdy,score,sage) values(xxx,xx,xx),(xxx,xx,xx),(xxx,xx,xx) -->
<insert id="testForeach02" parameterType="java.util.List">
    insert into student(sid,sname,sex,sdy,score,sage) 
    <foreach collection="list" open="values" close="" index="i" item="s" separator=",">
        (#{i}+1000,#{s.sname},#{s.sex},#{s.sdy},#{s.score},#{s.sage})
    </foreach>
</insert>

2.7 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>

3 动态sql的条件中怎么获取参数的值

3.1 参数是对象:直接通过属性名获取参数对象对应的属性值

<!-- 参数是对象:test中变量名和参数对象的属性名一致即可 -->
<!--  如果score和sex,sage有效 就作为查询条件  如果无效就查询所有
 public List<Student> getAll20(Student)-->
<select id="getAll20" resultType="Student" parameterType="Student">
    select * from student 
    <where>
        <!-- 标签test条件中的变量score/sex/sage 必须和参数对象Student的属性名一致即可 -->
        <if test="score != null">
            score >= #{0} and  <!-- 在sql片段中可以使用索引来 获取占位符的值 -->
        </if>
        <if test="sex != null">
            sex >= #{1} and
        </if>
        <if test="sage != null">
            sage >= #{2} 
        </if>
    </where>
</select>

3.2 参数是多个单值参数时:通过paramx来指向第x个参数的值

<!-- 多值参数:使用paramX来指向第x的参数的值 -->
<!--  如果score和sex,sage有效 就作为查询条件  如果无效就查询所有
 public List<Student> getAll21(Float score,String sex,Integer sage)-->
<select id="getAll21" resultType="Student">
    select * from student 
    <where>
        <!-- 错误写法:会在参数对象中找score属性:-->
        <if test="param1 != null">
            score >= #{0} and  <!-- 在sql片段中可以使用索引来 获取占位符的值 -->
        </if>
        <if test="param2 != null">
            sex >= #{1} and
        </if>
        <if test="param3 != null">
            sage >= #{2} 
        </if>

    </where>
</select>

3.3 参数是一个 并且是单值参数时:通过_parameter来指向此唯一的单值参数

<!-- 如果说只有一个参数:但不是对象 而是单值参数时:可以通过parameter来指向此唯一参数的值 -->
<!--  如果score和sex,sage有效 就作为查询条件  如果无效就查询所有
 public List<Student> getAll22(Float score)-->
<select id="getAll22" resultType="Student"  parameterType="float">
    select * from student 
    <where>
        <if test="_parameter != null">
            score >= #{0}  <!-- 在sql片段中可以使用索引来 获取占位符的值 -->
        </if>
    </where>
</select>

4 反向工程

4.0 概念

持久层框架的一个功能:实现由表自动生成实体类和mapper接口等
                  由实体类自动生成表

4.1 导包

log4j
jdbc
myabtis
mybatis-generator-core-1.3.2.jar

image-20230104142924326

4.2 创建表

SHOW CREATE TABLE student;
CREATE TABLE `student` (
  `sid` INT(11) NOT NULL AUTO_INCREMENT,
  `sname` VARCHAR(100) DEFAULT NULL,
  `sex` CHAR(1) DEFAULT NULL,
  `sage` INT(11) DEFAULT NULL,
  `sdy` TINYINT(1) DEFAULT NULL,
  `score` FLOAT(4,1) DEFAULT NULL,
  PRIMARY KEY (`sid`)
) ENGINE=INNODB AUTO_INCREMENT=1004 DEFAULT CHARSET=utf8;
ALTER TABLE teacher ADD tsalary FLOAT(9,2);
ALTER TABLE teacher ADD tsex CHAR(1);
UPDATE teacher SET tsalary=TRUNCATE(RAND()*100000,0),tsex=IF(RAND()>0.5,"男","女");
SHOW CREATE TABLE teacher;
CREATE TABLE `teacher` (
  `tid` INT(11) NOT NULL AUTO_INCREMENT,
  `tname` VARCHAR(100) DEFAULT NULL,
  `tage` INT(11) DEFAULT NULL,
  `tsalary` FLOAT(9,2) DEFAULT NULL,
  `tsex` CHAR(1) DEFAULT NULL,
  PRIMARY KEY (`tid`)
) ENGINE=INNODB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;

4.3 创建反向工程的配置文件:

名字随意
位置随意
<?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 >  
            <!-- suppress禁止 -->
            <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_1" 
            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="smail" />  
        </table>
        <table schema="" tableName="teacher"  
            domainObjectName="Teacher" enableCountByExample="false"  
            enableDeleteByExample="false" enableSelectByExample="false"  
            enableUpdateByExample="false">  
            <!-- schema即为数据库名 tableName为对应的数据库表, domainObjectName是要生成的实体类的名字, enable*ByExample指的是否生成 对应的example类,Mybatis Generator默认设置会生成一大堆罗哩罗嗦的Example类,主要是用各种不同的条件来操作数据库,大部分是用不到的,用到的时候手工修改mapper和接口文件就行了   -->  
          
        </table>    
  
    </context>  
</generatorConfiguration>  

4.4 为反向工程创建一个启动类

package test01;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;

public class Test01 {
	public static void main(String[] args) throws Exception{
		    List<String> warnings = new ArrayList<String>();
		    boolean overwrite = true;
		    File configFile = new File("src/generater_config.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);
	}
}

4.5 运行就生成:实体类+mapper接口+mapper映射文件

image-20230104145358237

4.6 注意

1:反向工程生成的内容不是一劳永逸的:可以根据需求更改
2:专门有个项目用于反向工程 把生成的文件添加到开发项目中

5 mybatis的缓存

参考:https://www.cnblogs.com/happyflyingpig/p/7739749.html

5.0 概念

缓存是所有持久层框架都具有的一种功能:把每次的请求得的sql语句和请求结果以键值对的形式存储起来
                               当再次请求相同内容时 不再去访问数据库 而是直接使用上一次请求的结果
缓存的作用:降低数据库服务器的压力+提高查询效率
          一旦执行了dml语句:缓存就需要清空
mybatis的一级缓存:基于sqlsession的缓存:

5.1 一级缓存

image-20230104150501642

  Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlSession而言。所以在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。
  • 一级缓存的生命周期
   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对象的数据,但是该对象可以继续使用
  • 代码测试
               //1 加载核心配置文件 创建SqlSessionFactory对象
				InputStream inputStream = Resources.getResourceAsStream("mybatis_config.xml");
				SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
				//2 通过SqlSessionFactory对象和SqlSession对象
				SqlSession sqlSession=sqlSessionFactory.openSession();
		        StudentMapper sm=sqlSession.getMapper(StudentMapper.class);
		        System.out.println(sm.selectByPrimaryKey(1));
		        System.out.println("-----");
		        //使用了缓存
		        System.out.println(sm.selectByPrimaryKey(1));
		        //sqlSession.clearCache();
		        //注意2:sqlsession调用了clearCache方法:清空缓存:一级缓存清空
		        //注意3:如果当前sqlsession执行了dml语句:一级缓存清空
		        sm.deleteByPrimaryKey(3);
		        System.out.println("-----");
		        System.out.println(sm.selectByPrimaryKey(1));
				//5 关闭session
				sqlSession.close();
				//重新获取sqlsession
				//注意1:sqlsession调用close方法:关闭连接后:一级缓存清空
//				sqlSession=sqlSessionFactory.openSession();
//				sm=sqlSession.getMapper(StudentMapper.class);
//				System.out.println("-----");
//		        System.out.println(sm.selectByPrimaryKey(1));

5.2 二级缓存

1 概念

image-20230104153513703

二级缓存是基于sqlsesssionfactory的缓存:
二级缓存需要持久化保存到文件中

2 步骤

  • 实体类实现序列化接口
public class Student  implements Serializable{}
  • 在核心配置文件中生命使用二级缓存
  <settings>
      ...
       <!--这个配置使全局的映射器(二级缓存)启用或禁用缓存-->
       <setting name="cacheEnabled" value="true" />
  </settings>
  • 在使用二级缓存的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"/>
  • 在使用缓存的sql标签中指定使用二级缓存
<!--可以通过设置useCache来规定这个sql是否开启缓存,ture是开启,false是关闭-->
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer"  useCache="true">
    select 
    <include refid="Base_Column_List" />
    from student
    where sid = #{sid,jdbcType=INTEGER}
</select>
<select id="getAll02" resultType="Student"  useCache="true">
    select * from student
</select>

3 测试

package test01;

import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;

import com.zhiyou100.mapper.StudentMapper;

public class Test03 {
	public static void main(String[] args) throws Exception{
		       //1 加载核心配置文件 创建SqlSessionFactory对象
				InputStream inputStream = Resources.getResourceAsStream("mybatis_config.xml");
				SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
				//2 通过SqlSessionFactory对象和SqlSession对象
				SqlSession sqlSession=sqlSessionFactory.openSession();
		        StudentMapper sm=sqlSession.getMapper(StudentMapper.class);
		        System.out.println(sm.selectByPrimaryKey(1));
		        System.out.println("-----");
		        System.out.println("获取所有::使用缓存:"+sm.getAll02());
		        System.out.println("-----");
		        System.out.println("获取所有::不使用缓存:"+sm.getAll03());
		        System.out.println("-----");
				//5 关闭session
				sqlSession.close();
				//重新获取sqlsession
				//注意1:sqlsession调用close方法:关闭连接后:一级缓存清空
				sqlSession=sqlSessionFactory.openSession();
				sm=sqlSession.getMapper(StudentMapper.class);
				
		        System.out.println(sm.selectByPrimaryKey(1));
		        System.out.println("-----");
		        System.out.println("获取所有::使用缓存:"+sm.getAll02());
		        System.out.println("-----");
		        System.out.println("获取所有::不使用缓存:"+sm.getAll03());
	}

}

6 模拟mybatis的原始dao方式

6.1 数据库准备

CREATE TABLE `student` (
  `sid` int(11) NOT NULL AUTO_INCREMENT,
  `sname` varchar(100) DEFAULT NULL,
  `sex` char(1) DEFAULT NULL,
  `sage` int(11) DEFAULT NULL,
  `sdy` tinyint(1) DEFAULT NULL,
  `score` float(4,1) DEFAULT NULL,
  PRIMARY KEY (`sid`)
) ENGINE=InnoDB AUTO_INCREMENT=1005 DEFAULT CHARSET=utf8

6.2 创建项目:模拟mybatis的所有内容

需要jdbc驱动jar

image-20230105110347444

6.3 创建实体类

必须有无参数的构造方法
package com.zhiyou100.entity;

import java.io.Serializable;

public class Student  implements Serializable{
    private Integer sid;

    private String sname;

    private String sex;

    private Integer sage;

    private Boolean sdy;

    private Float score;

    public Integer getSid() {
        return sid;
    }

    public void setSid(Integer sid) {
        this.sid = sid;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname == null ? null : sname.trim();
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex == null ? null : sex.trim();
    }

    public Integer getSage() {
        return sage;
    }

    public void setSage(Integer sage) {
        this.sage = sage;
    }

    public Boolean getSdy() {
        return sdy;
    }

    public void setSdy(Boolean sdy) {
        this.sdy = sdy;
    }

    public Float getScore() {
        return score;
    }

    public void setScore(Float score) {
        this.score = score;
    }

	@Override
	public String toString() {
		return "Student [sid=" + sid + ", sname=" + sname + ", sex=" + sex + ", sage=" + sage + ", sdy=" + sdy
				+ ", score=" + score + "]";
	}

	public Student(Integer sid, String sname, String sex, Integer sage, Boolean sdy, Float score) {
		super();
		this.sid = sid;
		this.sname = sname;
		this.sex = sex;
		this.sage = sage;
		this.sdy = sdy;
		this.score = score;
	}

	public Student() {
		super();
	}
	
    
}

6.4 准备

  • 工具类
package moni.mybatis;

import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;

public class Utils {
	//读取xml为documnet对象
	public static Document  xml2Doc(InputStream in){
		try {
			DocumentBuilder documentBuilder=DocumentBuilderFactory.newInstance().newDocumentBuilder();
		    return documentBuilder.parse(in);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	//把字符串转换为字段对应的类型
	public static Object changeType(String value,Class type)throws Exception{
		if(type==byte.class || type==Byte.class){
			return Byte.parseByte(value);
		}
		if(type==short.class || type==Short.class){
			return Short.parseShort(value);
		}
		if(type==int.class || type==Integer.class){
			return Integer.parseInt(value);
		}
		if(type==char.class || type==Character.class){
			return value.indexOf(0);
		}
		if(type==long.class || type==Long.class){
			return Long.parseLong(value);
		}
		if(type==float.class || type==Float.class){
			return Float.parseFloat(value);
		}
		if(type==double.class || type==Double.class){
			return Double.parseDouble(value);
		}
		if(type==boolean.class || type==Boolean.class){
			return Boolean.parseBoolean(value);
		}
		if(type==Date.class){
			return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(value);
		}
		return value;
	}
	//获取mybatis中所有占位符的名字
	public static List<String> parseMybatisSql(String sql){
		List<String> names=new ArrayList<String>();
		//) values(#{sname},#{sex},#{sdy},#{sbirth},#{score},#{sphoto})
		int indexStart=0;
		while(true){
			indexStart=sql.indexOf("#{",indexStart);
			if(indexStart==-1){
				break;
			}
			int indexEnd=sql.indexOf("}",indexStart);
			//截取子串
			String name=sql.substring(indexStart+2, indexEnd);
			names.add(name);
			indexStart++;
		}
		return names;
	}
}

  • 核心配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
  <environments default="development">
    <environment id="development">
      <!-- 事务管理方式: -->
      <transactionManager type="JDBC"/>
      <!-- 定义数据源:指定连接数据库的四大参数 -->
      <dataSource type="POOLED">
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/db_1?characterEncoding=utf-8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
      <mapper resource="com/zhiyou100/mapper/StudentMapper.xml"/>
  </mappers>
</configuration>
  • mapper映射文件
<?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="com.zhiyou100.mapper.StudentMapper" >
      <select id="getOne"  parameterType="int" resultType="com.zhiyou100.entity.Student">
	       select * from student where sid=#{sid}
	  </select>
	  <select id="getAll"   resultType="com.zhiyou100.entity.Student">
	       select * from student
	  </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},sex=#{sex},sage=#{sage},sdy=#{sdy},score=#{score} where sid=#{sid}
	  </update>
	  <insert id="addOne" parameterType="com.zhiyou100.entity.Student">
	      insert into student(sname,sex,sdy,sage,score) values(#{sname},#{sex},#{sdy},#{sage},#{score})
	  </insert>
</mapper>
  • 创建一个类描述所有的sql标签
package moni.mybatis;

public class SqlElement {
	private String eleName;
	private String eleId;
	private String parameterType;
	private String resultType;
	private String sql;
	public String getEleName() {
		return eleName;
	}
	public void setEleName(String eleName) {
		this.eleName = eleName;
	}
	public String getEleId() {
		return eleId;
	}
	public void setEleId(String eleId) {
		this.eleId = eleId;
	}
	public String getParameterType() {
		return parameterType;
	}
	public void setParameterType(String parameterType) {
		this.parameterType = parameterType;
	}
	public String getResultType() {
		return resultType;
	}
	public void setResultType(String resultType) {
		this.resultType = resultType;
	}
	public String getSql() {
		return sql;
	}
	public void setSql(String sql) {
		this.sql = sql;
	}
	@Override
	public String toString() {
		return "SqlElement [eleName=" + eleName + ", eleId=" + eleId + ", parameterType=" + parameterType
				+ ", resultType=" + resultType + ", sql=" + sql + "]";
	}
	public SqlElement(String eleName, String eleId, String parameterType, String resultType, String sql) {
		super();
		this.eleName = eleName;
		this.eleId = eleId;
		this.parameterType = parameterType;
		this.resultType = resultType;
		this.sql = sql;
	}

}

6.5 创建sqlsessionfactory类

1 读取核心配置文件中连接数据库的四大参数
2 读取mapper映射文件:把所有的sql标签读成sqlElement对象
package moni.mybatis;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.nio.channels.FileLockInterruptionException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class SqlSessionFactory {
	private InputStream in;
	private static Map<String, String> jdbcMap;
    private static String mapperPath;
    public static Map<String, SqlElement> sqlElementMap;
	public SqlSessionFactory(InputStream in) {
		this.in = in;
		Document doc=Utils.xml2Doc(in);
		//获取连接数据库的四大参数
		//1 获取<dataSource type="POOLED">标签
		Element eleDS=(Element)doc.getElementsByTagName("dataSource").item(0);
		jdbcMap=new HashMap<String, String>();
		//2 获取其所有的property属性
		NodeList propertyList=eleDS.getElementsByTagName("property");
		for (int i = 0; i < propertyList.getLength(); i++) {
			  Element elePro=(Element)propertyList.item(i);
			  // 3 获取其name和value属性:<property name="driver" value="com.mysql.jdbc.Driver"/>
			  jdbcMap.put(elePro.getAttribute("name"), elePro.getAttribute("value"));
		}
		//获取sql映射文件所在的位置
		// <mapper resource="com/zhiyou100/mapper/StudentMapper.xml"/>
		mapperPath=((Element)doc.getElementsByTagName("mapper").item(0)).getAttribute("resource");
		
		//注册驱动
		try {
			Class.forName(jdbcMap.get("driver"));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		
		//读取此sql映射文件中的所有sql标签::装入sqlElementMap
		sqlElementMap=new HashMap<String, SqlElement>();
		try {
			//获取的路径前面加src
			mapperPath="src/"+mapperPath;
			Document docSql=Utils.xml2Doc(new FileInputStream(mapperPath));
			//获取其mapper标签
			Element eleMapper=(Element)docSql.getElementsByTagName("mapper").item(0);
			//获取其下的所有子标签
			NodeList sqlEleList=eleMapper.getChildNodes();
			for (int i = 0; i < sqlEleList.getLength(); i++) {
				if(sqlEleList.item(i) instanceof Element){
					Element sqlEleZi=(Element)sqlEleList.item(i);
					//获取标签的所有信息 封装为SqlElement对象
					String eleName=sqlEleZi.getNodeName();
					String eleId=sqlEleZi.getAttribute("id");
					String parameterType=sqlEleZi.getAttribute("parameterType");
					String resultType=sqlEleZi.getAttribute("resultType");
					String sql=sqlEleZi.getTextContent().trim();
					sqlElementMap.put(eleId, new SqlElement(eleName, eleId, parameterType, resultType, sql));
				}
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		
		
	}
	public SqlSession openSession() {
		try {
			//每个sqlsession对应一个数据库的连接
			Connection con=DriverManager.getConnection(jdbcMap.get("url"), jdbcMap.get("username"), jdbcMap.get("password"));
			return new SqlSession(con);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		
	}
}

6.6 创建sqlsession

执行所有的sql标签中的sql语句
package moni.mybatis;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SqlSession {
	private Connection con;
	public SqlSession(Connection con){
		this.con=con;
	}
	public void close(){
		try {
			con.close();
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}
	public Object selectOne(String id,Object...args){
		List list=(List)executeSql(id, args);
		return list.get(0);
	}
	public List selectList(String id,Object...args){return (List)executeSql(id, args);}
	public int delete(String id,Object...args){return (Integer)executeSql(id, args);}
	public int update(String id,Object...args){return (Integer)executeSql(id, args);}
	public int insert(String id,Object...args){return (Integer)executeSql(id, args);}
	
	private Object executeSql(String id,Object...args){
		//通过id获取对应的sqlelement对象
		SqlElement sqlElement=SqlSessionFactory.sqlElementMap.get(id);
		
		//获取sql:中所有占位符的名字
		List<String> names=Utils.parseMybatisSql(sqlElement.getSql());
		
		//替换sql中的#{xxx}
		String sql=sqlElement.getSql().replaceAll("#\\{[0-9a-zA-Z_$]+\\}", "?");
		
		try {
			//获取预编译对象
			PreparedStatement sta=con.prepareStatement(sql);
			
			//给占位符赋值:
			if(names.size()==1){//如果说只有一个占位符:直接拿参数赋值即可
				sta.setObject(1, args[0]);
			}else if(names.size()>1){//如果说有多个占位符:拿参数对象的属性 赋值给对应的占位符
				//获取字节码文件对象
				Class cla=args[0].getClass();
				for (int i=0;i<names.size();i++) {
					Field field=cla.getDeclaredField(names.get(i));
					field.setAccessible(true);
					Object fieldValue=field.get(args[0]);
					sta.setObject(i+1, fieldValue);
				}
			}
			//执行sql
			//如果是select 需要解析结果集
			//如果是dml  需要获取影响的行数
			if(sqlElement.getEleName().equals("select")){
				ResultSet set=sta.executeQuery();
				//把结果集封装为对象
				List list=new ArrayList();
				Class cla=Class.forName(sqlElement.getResultType());
				while(set.next()){
					Object obj=cla.newInstance();//每行要被解析成一个对象
					Field[] fieldArr=cla.getDeclaredFields();
					for (Field field : fieldArr) {
						field.setAccessible(true);
						field.set(obj, set.getObject(field.getName()));
					}
					list.add(obj);
				}
				set.close();
				return list;
				
			}else{
				int hang=sta.executeUpdate();
				sta.close();
				return hang;
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

}

6.7 测试

package test01;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import com.zhiyou100.entity.Student;

import moni.mybatis.SqlSession;
import moni.mybatis.SqlSessionFactory;

public class Test01 {
	public static void main(String[] args) throws Exception{
		       //1 加载核心配置文件 创建SqlSessionFactory对象
				InputStream inputStream = new FileInputStream("src/mybatis_config.xml");
				SqlSessionFactory sqlSessionFactory = new SqlSessionFactory(inputStream);
				//2 通过SqlSessionFactory对象和SqlSession对象
				SqlSession sqlSession=sqlSessionFactory.openSession();
				System.out.println("获取一个:"+sqlSession.selectOne("getOne", 1));
				System.out.println("获取所有:"+sqlSession.selectList("getAll", null));
				System.out.println("添加一个:"+sqlSession.insert("addOne", new Student(null, "模拟1", "妖", 100, true, 11f)));
				System.out.println("删除一个:"+sqlSession.delete("deleteOne", 3));
				System.out.println("修改一个:"+sqlSession.update("updateOne", new Student(4, "模拟4", "妖", 140, true, 44f)));
		       
				//5 关闭session
				sqlSession.close();
	}

}

6.8 改进 一次加载多个sql映射文件

  • 创建teacher表
  • 创建Teacher类
  • 创建sql映射文件
  • 在核心配置文件中引入此sql映射文件
  • 更改SqlSessionFactory中读取mapper标签时 不再是一个 而是多个
//读取此sql映射文件中的所有sql标签::装入sqlElementMap
		sqlElementMap=new HashMap<String, SqlElement>();
		try {
			for (String mapperPath : mapperPaths) {
				//获取的路径前面加src
				mapperPath="src/"+mapperPath;
				Document docSql=Utils.xml2Doc(new FileInputStream(mapperPath));
				//获取其mapper标签
				Element eleMapper=(Element)docSql.getElementsByTagName("mapper").item(0);
				//获取其下的所有子标签
				NodeList sqlEleList=eleMapper.getChildNodes();
				for (int i = 0; i < sqlEleList.getLength(); i++) {
					if(sqlEleList.item(i) instanceof Element){
						Element sqlEleZi=(Element)sqlEleList.item(i);
						//获取标签的所有信息 封装为SqlElement对象
						String eleName=sqlEleZi.getNodeName();
						String eleId=sqlEleZi.getAttribute("id");
						String parameterType=sqlEleZi.getAttribute("parameterType");
						String resultType=sqlEleZi.getAttribute("resultType");
						String sql=sqlEleZi.getTextContent().trim();
						sqlElementMap.put(eleId, new SqlElement(eleName, eleId, parameterType, resultType, sql));
					}
				}
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
  • 测试
package test01;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import com.zhiyou100.entity.Student;
import com.zhiyou100.entity.Teacher;

import moni.mybatis.SqlSession;
import moni.mybatis.SqlSessionFactory;

public class Test01 {
	public static void main(String[] args) throws Exception{
		       //1 加载核心配置文件 创建SqlSessionFactory对象
				InputStream inputStream = new FileInputStream("src/mybatis_config.xml");
				SqlSessionFactory sqlSessionFactory = new SqlSessionFactory(inputStream);
				//2 通过SqlSessionFactory对象和SqlSession对象
				SqlSession sqlSession=sqlSessionFactory.openSession();
				System.out.println("对student进行增删改查:::");
				System.out.println("获取一个:"+sqlSession.selectOne("getOneStudent", 1));
				System.out.println("获取所有:"+sqlSession.selectList("getAllStudent", null));
				System.out.println("添加一个:"+sqlSession.insert("addOneStudent", new Student(null, "模拟2", "妖", 100, true, 11f)));
				System.out.println("删除一个:"+sqlSession.delete("deleteOneStudent", 5));
				System.out.println("修改一个:"+sqlSession.update("updateOneStudent", new Student(6, "模拟6", "妖", 140, true, 44f)));
				System.out.println("对Teacher进行增删改查:::");
				System.out.println("获取一个:"+sqlSession.selectOne("getOneTeacher", 1));
				System.out.println("获取所有:"+sqlSession.selectList("getAllTeacher", null));
				System.out.println("添加一个:"+sqlSession.insert("addOneTeacher", new Teacher(null, "校老师", 34, 10000f, "男")));
				System.out.println("删除一个:"+sqlSession.delete("deleteOneTeacher", 3));
				System.out.println("修改一个:"+sqlSession.update("updateOneTeacher", new Teacher(2, "田老师", 32, 20000f, "妖")));
				//5 关闭session
				sqlSession.close();
	}

}

  • 所有sql映射文件的sql标签的id必须唯一

7 模拟mybatis的mapper代理方式

7.1 创建sql映射文件对应的类:

技术能力有限:不能通过接口获取代理对象 只能通过类获取其代理对象
package com.zhiyou100.mapper;

import java.util.List;

import com.zhiyou100.entity.Student;

//动态代理还是cglib代理 都需要指定目标对象:::目前无法实现由接口获取一个接口的实现类对象
public class StudentMapper {
//	 <select id="getOneStudent"  parameterType="int" resultType="com.zhiyou100.entity.Student">
//	     select * from student where sid=#{sid}
//	</select>
	public Student getOneStudent(int sid){return null;}
//	<select id="getAllStudent"   resultType="com.zhiyou100.entity.Student">
//	     select * from student
//	</select>
	public List<Student> getAllStudent(){return null;}
//	<delete id="deleteOneStudent" parameterType="int">
//	    delete from student where sid=#{sid}
//	</delete>
	public int deleteOneStudent(int sid){return 0;}
//	<update id="updateOneStudent" parameterType="com.zhiyou100.entity.Student">
//	    update student set sname=#{sname},sex=#{sex},sage=#{sage},sdy=#{sdy},score=#{score} where sid=#{sid}
//	</update>
	public int updateOneStudent(Student s){return 0;}
//	<insert id="addOneStudent" parameterType="com.zhiyou100.entity.Student">
//	    insert into student(sname,sex,sdy,sage,score) values(#{sname},#{sex},#{sdy},#{sage},#{score})
//	</insert>
	public int addOneStudent(Student s){return 0;}

}

7.2 在sqlsessioon中添加方法getMapper

getMapper方法中要获取指定类的代理对象:对目标对象的方法进行改进:去调用方法名对应的sql标签
public Object getMapper(Class cla)throws Exception{
    Object obj=cla.newInstance();
    class ProxyFactroy03 implements MethodInterceptor{
        //4 定义引用 记录被代理对象
        private Object target;
        //通过方法给被代理对象引用赋值
        public void setTarget(Object obj){
            this.target=obj;
        }
        //5 创建方法获取代理对象:::被代理对象的子类对象
        public Object newInstance(){
            //工具类
            Enhancer en = new Enhancer();//创建一个增强工具类对象
            //设置父类
            en.setSuperclass(target.getClass());
            //设置回调函数的对象
            en.setCallback(this);
            //创建代理对象---是目标类的子类对象
            return en.create();
        }

        //6 代理对象的方法实现对被代理对象功能的控制
        //参数1:arg0代理对象
        //参数2:method被代理对象的方法
        //参数3:arg2被代理对象的方法的参数列表
        //参数4:arg3被代理对象方法的代理
        public Object intercept(Object arg0, Method method, Object[] arg2, MethodProxy arg3) throws Throwable {
            //执行method对应的sql标签
            //获取方法名
            String methodName=method.getName();
            Object result=executeSql(methodName, arg2);
            System.out.println(method.getReturnType()+"::"+result.getClass());
            if (!(method.getReturnType()==int.class||method.getReturnType()==Integer.class||method.getReturnType()==List.class||method.getReturnType()==ArrayList.class)) {
                List list=(List)result;
                result=list.get(0);
            }
            return result;
        }
    }
    ProxyFactroy03 factroy=new ProxyFactroy03();
    factroy.setTarget(obj);
    return factroy.newInstance();
}

7.3 测试

package test01;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import com.zhiyou100.entity.Student;
import com.zhiyou100.entity.Teacher;
import com.zhiyou100.mapper.StudentMapper;

import moni.mybatis.SqlSession;
import moni.mybatis.SqlSessionFactory;

public class Test02 {
	public static void main(String[] args) throws Exception{
		       //1 加载核心配置文件 创建SqlSessionFactory对象
				InputStream inputStream = new FileInputStream("src/mybatis_config.xml");
				SqlSessionFactory sqlSessionFactory = new SqlSessionFactory(inputStream);
				//2 通过SqlSessionFactory对象和SqlSession对象
				SqlSession sqlSession=sqlSessionFactory.openSession();
				StudentMapper studentMapper=(StudentMapper)sqlSession.getMapper(StudentMapper.class);
				System.out.println("获取一个:"+studentMapper.getOneStudent(1));
				System.out.println("获取所有:"+studentMapper.getAllStudent());
				System.out.println("添加一个:"+studentMapper.addOneStudent( new Student(null, "模拟777777", "妖", 100, true, 11f)));
				System.out.println("删除一个:"+studentMapper.deleteOneStudent(4));
				System.out.println("修改一个:"+studentMapper.updateOneStudent(new Student(6, "模拟666666", "妖", 100, true, 11f)));
				sqlSession.close();
	}

}

  • 30
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值