发表于: 2016-09-14 15:06:04

1 2354


内容略多就把12、13号的合并了

一、今天完成

基于Mybatis的多种场景多种模式的Mysql数据库操作,选取了以前项目中经常涉及到数据库操作。

1.通用动作

log4j.properties中
#Global logging configuration
log4j.rootLogger=DEBUG, stdout
#Console output
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5d [%t] - %m%n
XXXTest.java中
//会话工厂
private SqlSessionFactory sqlSessionFactory;
private Logger log = Logger.getLogger(this.getClass());
public void before() throws Exception{
   //配置文件SqlMapConfig.xml
   String resource = "Config/SqlMapConfig.xml";
   //加载配置文件到输入流
   InputStream is = Resources.getResourceAsStream(resource);
   //创建会话工厂
   sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
}
public void testXXXXX() throws Exception {
   log.info("打印日志:");
   //通过sqlSessionFactory创建sqlSession
   SqlSession sqlSession = sqlSessionFactory.openSession();
2.案例
2.1 根据主键查询单条用户的全部信息
1)原始开发
SqlMapConfig.xml中
<mappers>
 <mapper resource="Config/SqlXML/Enroll.xml"/>
Enroll.xml中
<mapper namespace="haha">
<!--mapper.xml文件中配置很多sql语句,执行语句时,封装为MappedStatement对象的mapper.xmlStatement为单位管理sql语句-->
 <!--id标识一个Statement-->
 <!--#{} 替代一个占位符,如果是简单类型参数,可随意命名 -->
 <!--parameterType 参数类型-->
 <!--resultType 输出类型,指定单条sql映射到pojo类型-->
 <select id="findOneById" parameterType="int" resultType="Bean.Enroll">
   SELECT * FROM enroll WHERE student_id = #{id}
 </select>
FirstOriginal.java中
//通过sqlSession操作查询数据库
//第一个参数:statement位置 = namespace + statement
//第二个参数:传入的参数
Enroll enroll = null;
try {
   enroll = sqlSession.selectOne("haha.findOneById", 1);
} catch (Exception e) {
   e.printStackTrace();
} finally {
   //关闭sqlSession
   sqlSession.close();
}
System.out.println(enroll.toString());
2)mapper代理开发
java、resource根目录下分别建mapper包
SqlMapConfig.xml中
<mappers>
 <mapper resource="Config/Mapper/FirstMapper.xml"/>
FirstMapper.java中
public interface FirstMapper {
   public Enroll findOneById(int id)throws Exception;
FirstMapper.xml中
<mapper namespace="Mapper.FirstMapper">
   <select id="findOneById" parameterType="int" resultType="Bean.Enroll">
       SELECT * FROM enroll WHERE student_id = #{id}
   </select>
FirstMapperTest.java中
SqlSession sqlSession = sqlSessionFactory.openSession();
FirstMapper firstMapper = sqlSession.getMapper(FirstMapper.class);
Enroll enroll = firstMapper.findOneById(1);
System.out.println(enroll.toString());
3)注解开发
SqlMapConfig.xml中
<mappers>
 <mapper class="Annotation.FirstAnnotation"/>
或者<package name="Annotation" />
FirstAnnotation.java中
public interface FirstMapper {
@Select("select * from enroll where student_id = #{student_id}")
public Enroll findById(int student_id)throws Exception;
FirstAnnotationTest.java中跟FirstMapperTest.java类似
2.根据模糊匹配批量查询所有符合用户的全部信息
1)原始
Enroll.xml中
<select id="searchByMatchName" parameterType="String" resultType="Bean.Enroll">
 SELECT * FROM enroll WHERE student_name LIKE '%' #{name} '%'
</select>
FirstOriginal.java中
public void testSearchByMatchName(){
...
List<Enroll> list = new ArrayList<Enroll>();
String name = "";
list = sqlSession.selectList("haha.searchByMatchName", name);
2)代理
FirstMapper.java中
public Enroll findOneById(int id)throws Exception;
FirstMapper.xml中
<select id="searchByMatchName" parameterType="String" resultType="Bean.Enroll">
   SELECT * FROM enroll WHERE student_name LIKE '%' #{name} '%'
</select>
FirstMapperTest.java中,通用的不再写了
public void testSearchByMatchName()throws Exception{
...
List<Enroll> list = new ArrayList<Enroll>();
String name = "";
list = firstMapper.findOneById(name);
3)注解
FirstAnnotation.java中
@Select("SELECT * FROM enroll WHERE student_name LIKE '%' #{name} '%'")
public List<Enroll> searchByMatchName(String name)throws Exception;
3.插入多条用户信息
1)原始
Enroll.xml中
<insert id="insertBatch" parameterType="java.util.List">
 INSERT INTO enroll(student_name, create_time, update_time) VALUES
 <foreach collection="list" item="item" separator=",">
   (#{item.student_name},#{item.create_time},#{item.update_time})
 </foreach>
</insert>
FirstOriginal.java中
List<Enroll> list = new ArrayList<Enroll>();
list = addToList(list);
sqlSession.insert("haha.insertBatch", list);
sqlSession.commit();
...
public static List<Enroll> addToList(List<Enroll> list){
   for (int i = 2; i < 9; i++){
       Enroll enroll = new Enroll();
       enroll.setStudent_name("赵老" + i);
       enroll.setCreate_time(20160913);
       enroll.setUpdate_time(currentTime);
       list.add(enroll);
   }
   return list;
}
2)代理
FirstMapper.java中
public void insertBatch(List<Enroll> list)throws Exception;
FirstMapper.xml中
<insert id="insertBatch" parameterType="java.util.List">
   INSERT INTO enroll(student_name, create_time, update_time) VALUES
   <foreach collection="list" item="item" separator=",">
       (#{item.student_name},#{item.create_time},#{item.update_time})
   </foreach>
</insert>
FirstMapperTest.java中
List<Enroll> list = new ArrayList<Enroll>();
list = FirstOriginalTest.addToList(list);
FirstMapper firstMapper = sqlSession.getMapper(FirstMapper.class);
firstMapper.insertBatch(list);
sqlSession.commit();
3)注解
FirstAnnotation.java中
@InsertProvider(type = SqlProvider.class, method = "buildInsertBatch")
public void insertBatch(List<Enroll> list)throws Exception;
...
class SqlProvider{
   public String buildInsertBatch(final List<Enroll> list){
       return new SQL(){{
           INSERT_INTO("enroll");
           for(Enroll enroll: list){
               VALUES("student_name","#{enroll.student_name}");
               VALUES("create_time","#{enroll.create_time}");
               VALUES("update_time","#{enroll.update_time}");
           }
       }
       }.toString();
   }
}
4.向表传入一条pojo数据,如果数据的mobile_num已经存在则更新update_time,否则插入并返回数据库自动生成的student_id
数据库新增了一个字段mobile_num,varchar型;
设置关键字、唯一索引;
pojo类中增加同名String成员变量及对应方法。
1)原始
Enroll.xml中
<insert id="insertOrUpdate" parameterType="Bean.Enroll">
 <selectKey order="AFTER" resultType="int" keyProperty="student_id">
   SELECT LAST_INSERT_ID()
 </selectKey>
 INSERT INTO enroll(student_name, create_time, update_time, mobile_num)
 VALUES(#{student_name},#{create_time},#{update_time},#{mobile_num})
 ON DUPLICATE KEY UPDATE update_time = VALUES (update_time)
</insert>
FirstOriginal.java中
Enroll enroll = new Enroll();
enroll.setStudent_name("方脑壳");
enroll.setCreate_time(currentTime);
enroll.setUpdate_time(currentTime);
enroll.setMobile_num("18725900000");
System.out.println("before: " + enroll.getStudent_id());
sqlSession.insert("haha.insertOrUpdate", enroll);
sqlSession.commit();
...
System.out.println("after: " + enroll.getStudent_id());
5.更新student_id在[1,10]的update_time为当前时间
2)代理
FirstMapper.java中
public void updateBatch(long time)throws Exception;
FirstMapper.xml中
<update id="updateBatch" parameterType="long">
   UPDATE enroll SET update_time = #{time} WHERE student_id BETWEEN 1 AND 10
</update>
FirstMapperTest.java中
firstMapper.updateBatch(currentTime);
6.删除最近登陆时间介于[2016-09-11 0:00,2016-09-13 12:00]的用户并返回删除的用户
3)注解
FirstAnnotation.java中
@Delete("DELETE FROM enroll WHERE update_time > #{time}")

public void deleteBatchByDate(long time)throws Exception;


二、明天计划
1.学习spring、springMVC概念

2.学习基本的两者与mybatis结合的使用方法


三、遇到问题
1. <mapper class或<package name 的应用场景用到了mapper代理模式中,报错BuildingException,老大指正:实际作用是将接口与statement关联起来,适用于注解模式中。
2.模糊查询时用%报错,SELECT * FROM enroll WHERE student_name LIKE '%#{name}%' 自己试了几次,发现 SELECT * FROM enroll WHERE student_name LIKE '%' #{name} '%' 即可。
3.(重要)设定一个时间戳用于条件删除,
SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-DD hh:mm:ss");
long specifiedTime = sdf.parse("2016-09-13 00:00:00").getTime();
得到的时间与 long currentTime = new Date().getTime(); 有较大差异不符合需求
经曾李师兄提醒注意大小写 yyyy-MM-dd hh:mm:ss。
4.insert获取自增的主键ID时,这个ID是通过 selectKey 返回给插入的自定义类成员变量的,一直以为是普通返回值,重复看了几遍官方文档发现。

5.在多主键的enroll表中使用 INSERT INTO ... ON DUPLICATE KEY UPDATE  出现了实效的情况,百度搜索找到将其中一个主键设定为唯一索引 CREATE UNIQUE INDEX IDX_UID ON test(UID); 即可。


四、收获
1.Mybatis解决了JDBC的哪些问题
1)数据库频繁创建和关闭浪费性能
使用连接池:SqlMapConfig.xml中配置数据连接池
2)SQL语句是硬编码
将语句统一配置在文件中,修改sql不用修改java代码:将SQL语句放到XXXmapper.xml,与java代码隔离。
3)通过preparedstatement设置参数、位置是硬编码
sql中的占位符及对应参数类型放在配置文件中:XXXmapper.xml中将java对象映射至SQL语句,通过statement中的parameterType定义输入参数类型
4)遍历查询结果存在硬编码
自动将结果封装成pojo对象:通过statement中的resultType定义输出结果类型
2.junit测试
1)插入单条记录
2)按单挑student_id修改符合条件的记录的student_name、update_time
3)按student_id数组批量修改更新时间
3.mapper(代理)开发规范
1)文件规范
包名=代码根目录.mapper  文件名=表名+mapper.java
包名=Config根目录.mapper  文件名=表名+mapper.xml
namespace名=mapper类的相对路径
2)方法规范
mapper.xml中的sql的id = mapper.java中接口方法名
3)参数规范
mapper.xml中的statement的parameterType = mapper.java中入参
4)返回值规范
mapper.xml中的statement的resultType = mapper.java中返回值
4.注解开发的statement绑定
SqlMapConfig.xml中mapper的class加载方法,这种情况namespace好像没发挥作用。
单条<mapper class=""  />
批量<package name="" />
后面和spring整合后,spring的mapper扫描器让mappers不用再配置了



返回列表 返回列表
评论

    分享到