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&¶ms.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();
}
}