Mybatis进行CRUD
之前已经配置了MyBatis的使用环境以及其它一切所需要的基础文件,但是一直没说这个东西究竟时怎么样来操作数据库的。上一次的总结最后的Test类就是干这件事情的。
基础方式
在测试类的方法中,显然是要读取conf.xml文件的,然后用这个IO流创建一个SqlSessionFactory(SqlSessionFactoryBuilder().build(reader),build的第二个参数可以指定数据库环境,默认使用environments的default指定的);用SqlSessionFactory的openSession方法还能构造一个SqlSession实例。
Reader reader=Resources.getResourceAsReader("conf.xml");
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);//可以通过build的第二参数指定数据库环境
SqlSession sqlSession=sqlSessionFactory.openSession();
讲了这么多,其实这个SqlSession实例就相当于JDBC的Connection,不过干的事情更多些:SqlSession不止是声明了数据库信息,它的创建所依据的那个conf.xml文件中还声明了映射文件,所以所有即将用到的sql语句都是SqlSession实例所直接能够使用的;而JDBC中所有的sql语句都要自己现场手写,不易管理、修改起来很不方便。
在Mapper.xml中,每一个sql语句都是由namespace和id来唯一标识。而这里增删改查的方式就是直接定位到每一个Mapper.xml中的语句来实现数据库操作,定位方法是直接将这两个东西弄成一个String:
String statement="shopkeeper.personMapper."+"queryAll";
增删改查是调用SqlSession实例的对应的方法,其中第一个参数必须是唯一标识statement,后继的参数如同Mapper.xml文件中的一样如果没有就不写,要有的话只能有一个(多个就封装成对象);返回值稍作改变,Mapper.xml中无论返回值有多少个,都只写一个的情况,但是Java语言不能这样,要视情况改变(其实全写List也行,反正原理都是从游标读,然后返回值的多少其实是取决于你调用的SqlSession的方法,例如selectOne和selectLst):
Person person=sqlSession.selectOne(statement,1); List<Person> persons=sqlSession.selectList(statement); int count=sqlSession.insert(statement,person); int count=sqlSession.delete(statement,3); int count=sqlSession.update(statement,person);
由于我使用的事务方式是JDBC,增删改操作还是要commit的,做法为调用SqlSession.commit()方法。
完整的方法如下:
public static void queryPersonById() throws IOException {
Reader reader=Resources.getResourceAsReader("conf.xml");
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);//可以通过build的第二参数指定数据库环境
SqlSession sqlSession=sqlSessionFactory.openSession();
String statement="shopkeeper.personMapper.queryPersonById";
Person person=sqlSession.selectOne(statement,1);
System.out.println(person);
sqlSession.close();
reader.close();
}
public static void queryAllPerson() throws IOException {
Reader reader=Resources.getResourceAsReader("conf.xml");
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);//可以通过build的第二参数指定数据库环境
SqlSession sqlSession=sqlSessionFactory.openSession();
String statement="shopkeeper.personMapper."+"queryAll";
List<Person> persons=sqlSession.selectList(statement);
System.out.println(persons);
sqlSession.close();
reader.close();
}
public static void addPerson() throws IOException {
Reader reader=Resources.getResourceAsReader("conf.xml");
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);//可以通过build的第二参数指定数据库环境
SqlSession sqlSession=sqlSessionFactory.openSession();
String statement="shopkeeper.personMapper."+"addPerson";
Person person=new Person(19,"刘茜元",3);
int count=sqlSession.insert(statement,person);
sqlSession.commit();
System.out.println("增加了"+count+"个人");
sqlSession.close();
reader.close();
}
public static void deletePersonById() throws IOException {
Reader reader=Resources.getResourceAsReader("conf.xml");
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);//可以通过build的第二参数指定数据库环境
SqlSession sqlSession=sqlSessionFactory.openSession();
String statement="shopkeeper.personMapper."+"detelePersonById";
int count=sqlSession.delete(statement,3);
sqlSession.commit();
System.out.println("删除了"+count+"个人");
sqlSession.close();
reader.close();
}
public static void updatePersonById() throws IOException {
Reader reader=Resources.getResourceAsReader("conf.xml");
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);//可以通过build的第二参数指定数据库环境
SqlSession sqlSession=sqlSessionFactory.openSession();
String statement="shopkeeper.personMapper."+"updatePerson";
Person person=new Person();
person.setId(3);
person.setName("刘闹闹");
person.setAge(19);
int count=sqlSession.update(statement,person);
sqlSession.commit();
System.out.println("更新了"+count+"个人");
sqlSession.close();
reader.close();
}
mapper动态代理方式CRUD
也叫接口开发。
在基础方式中说JDBC不好时,点名批评了JDBC每一个sql语句都要手写,但是其实基础方式里面也是要手写每一个statement的,只不过是将sql语句简化为了namespace+id了。
但是我们要严于律己,仅仅做到这方面是远远不够的,最好能够达到直接调用方法就能指哪打哪。mapper动态代理就是干的这件事。
总的来说,Mapper动态代理的思路就是将Mapper.xml中的sql语句变成接口中的方法,约定之前的namespace成为接口名称,每一个id变成方法名,具体是怎么实现的就是MyBatis底层的事情了。
那么,这些接口就需要满足以下几个要求:
接口名为namespace;
方法名为id值;
输入的参数和mapper.xml的parameterType一致;
返回值如果是查询就必须和resultType一致,如果你想要得到增删改操作成功的结果数量,就可以写成int,如果不想要就写void。
有多个Mapper.xml文件就实现多个接口。匹配的过程是根据接口名找到mapper. xml文件,根据接口的方法名找到mapper. xml文件中的SQL标签。(那么问题来了,如果两个不同的mapper.xml中有id相同的sql语句怎么办?对应到java就是两个不同的接口有同名的方法)。
还有一个习惯是: SQL映射文件(mapper. xml)和接口放在同一个包中(注意修改conf. xml中加载mapper. xml文件的路径)。
执行
先得到接口的实例化对象:
personMapper personMapper =sqlSession.getMapper(personMapper.class);
再通过接口的实例化对象来调用其方法(返回值自取):
int count=personMapper.addPerson(person);
最后增删改别忘了commit。
完整的方法如下:
public static void queryPersonById() throws IOException {
Reader reader=Resources.getResourceAsReader("conf.xml");
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);//可以通过build的第二参数指定数据库环境
SqlSession sqlSession=sqlSessionFactory.openSession();
personMapper personMapper =sqlSession.getMapper(personMapper.class);
Person person=personMapper.queryPersonById(1);
System.out.println(person);
sqlSession.close();
reader.close();
}
public static void queryPersonByIdWithConverter() throws IOException {
Reader reader=Resources.getResourceAsReader("conf.xml");
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);//可以通过build的第二参数指定数据库环境
SqlSession sqlSession=sqlSessionFactory.openSession();
personMapper personMapper =sqlSession.getMapper(personMapper.class);
Person person=personMapper.queryPersonByIdWithConverter(1);
System.out.println(person);
sqlSession.close();
reader.close();
}
public static void queryAllPerson() throws IOException {
Reader reader=Resources.getResourceAsReader("conf.xml");
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);//可以通过build的第二参数指定数据库环境
SqlSession sqlSession=sqlSessionFactory.openSession();
personMapper personMapper =sqlSession.getMapper(personMapper.class);
List<Person> persons=personMapper.queryAll();
System.out.println(persons);
sqlSession.close();
reader.close();
}
public static void addPerson() throws IOException {
Reader reader=Resources.getResourceAsReader("conf.xml");
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);//可以通过build的第二参数指定数据库环境
SqlSession sqlSession=sqlSessionFactory.openSession();
Person person=new Person(19,"刘茜元",13);
personMapper personMapper =sqlSession.getMapper(personMapper.class);
int count=personMapper.addPerson(person);
sqlSession.commit();
System.out.println("增加了"+count+"个人");
sqlSession.close();
reader.close();
}
public static void addPersonWithConverter() throws IOException {
Reader reader=Resources.getResourceAsReader("conf.xml");
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);//可以通过build的第二参数指定数据库环境
SqlSession sqlSession=sqlSessionFactory.openSession();
Person person=new Person(19,"刘茜元",13);
personMapper personMapper =sqlSession.getMapper(personMapper.class);
int count=personMapper.addPersonWithConverter(person);
sqlSession.commit();
System.out.println("增加了"+count+"个人");
sqlSession.close();
reader.close();
}
public static void deletePersonById() throws IOException {
Reader reader=Resources.getResourceAsReader("conf.xml");
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);//可以通过build的第二参数指定数据库环境
SqlSession sqlSession=sqlSessionFactory.openSession();
personMapper personMapper =sqlSession.getMapper(personMapper.class);
int count=personMapper.detelePersonById(13);
sqlSession.commit();
System.out.println("删除了"+count+"个人");
sqlSession.close();
reader.close();
}
public static void updatePersonById() throws IOException {
Reader reader=Resources.getResourceAsReader("conf.xml");
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);//可以通过build的第二参数指定数据库环境
SqlSession sqlSession=sqlSessionFactory.openSession();
personMapper personMapper =sqlSession.getMapper(personMapper.class);
Person person=new Person();
person.setId(13);
person.setName("刘咯咯");
person.setAge(19);
int count=personMapper.updatePerson(person);
sqlSession.commit();
System.out.println("更新了"+count+"个人");
sqlSession.close();
reader.close();
}