MyBatis单表增删改查--XML实现
MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。
无论是用过的hibernate,mybatis,你都可以法相他们有一个共同点:
1. 从配置文件(通常是XML配置文件中)得到 sessionfactory.
2. 由sessionfactory 产生 session
3. 在session 中完成对数据的增删改查和事务提交等.
4. 在用完之后关闭session 。
5. 在java 对象和 数据库之间有做mapping 的配置文件,也通常是xml 文件。
1:实体类Student
建立一个简单的学生类,用来保存学生信息
package com.zhao.entity; import java.io.Serializable; public class Student implements Serializable { private static final long serialVersionUID = 1L; private int stu_id; private String stu_name; private String stu_gender; public Student() { } public Student(String stu_name, String stu_gender) { this.stu_name = stu_name; this.stu_gender = stu_gender; } public Student(int stu_id, String stu_name, String stu_gender) { this.stu_id = stu_id; this.stu_name = stu_name; this.stu_gender = stu_gender; } public int getStu_id() { return stu_id; } public void setStu_id(int stu_id) { this.stu_id = stu_id; } public String getStu_name() { return stu_name; } public void setStu_name(String stu_name) { this.stu_name = stu_name; } public String getStu_gender() { return stu_gender; } public void setStu_gender(String stu_gender) { this.stu_gender = stu_gender; } @Override public String toString() { return "Student [stu_id=" + stu_id + ", stu_name=" + stu_name + ", stu_gender=" + stu_gender + "]"; } }
2:jdbc.properties+Configuration.xml
myBatis的配置文件Configuration.xml和hibernate的配置文件hibernate.cfg.xml差不多。都是用于数据库连接的,驱动 url 账号 密码必不可少。我们可以用jdbc.properties来保存这些信息,前段时间搭建SSH架构的时候也是把数据库信息写到一个properties中。
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/mybatis username=root password=密码
1)Configuration.xml 是 mybatis 用来建立 sessionFactory 用的,里面主要包含了数据库连接相关东西。
2)Configuration里有 java 类所对应的别名,这个别名非常重要。在引用实体类的时候可以用别名来代替,就不用把实体类的全路径都写出来了。
3) Configuration.xml 里面 的
<mapper resource="com/zhao/entity/Student.xml" />是包含要映射的类的xml配置文件。
MyBatis的配置文件很好理解,必须做的两个事就是数据库的配置 和 要映射的类的配置文件,hibernate叫对象关系映射文件。这二者还是有区别的。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 引用jdbc.properties配置文件 --> <properties resource="jdbc.properties" /> <!-- 配置实体类的别名,配置实体类别名的目的是为了在引用实体类时可以使用实体类的别名来代替实体类,达到简写的目的 --> <typeAliases> <typeAlias alias="Student" type="com.zhao.entity.Student" /> <!-- 为com.zhao.entity包下的所有实体类配置别名,MyBatis默认的设置别名的方式就是去除类所在的包后的简单的类名 比如com.zhao.entity.Student这个实体类的别名就会被设置成Student <package name="com.zhao.entity"/> --> </typeAliases> <!-- development : 开发模式; work : 工作模式 --> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <!-- 配置数据库连接信息 --> <dataSource type="POOLED"> <property name="driver" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> </dataSource> </environment> </environments> <!-- 要映射的类的xml配置文件 --> <mappers> <mapper resource="com/zhao/entity/Student.xml" /> <mapper class="com.zhao.mapper.StudentMapper" /> </mappers> </configuration>
3:Student.xml
这个文件可能看起来比较复杂,不像hibernate那样清晰,他们二者是有区别的。
1:hibernate通过对象关系映射文件把实体类的属性和数据表的列对应起来,是在这个配置文件里完成对应的工作的,所有我们的对象关系映射文件看起来很简单,就是一些对应关系。只有完成了这个对应关系,我们才可以在代码中通过对实体类的操作实现数据库表信息的改变。注意,hibernate对表的操作是在代码中的。相应的出现了Query SQLQuery这些东西,都是为了方便我们操作数据表。
2:myBatis的映射配置文件中居然把数据表的操作写的这么清楚。虽然我也看着比较乱吧。没有了实体类和数据表一一对应的过程了,这是对hibernate的一个简化。
分析:下面完成了数据表student的增删改查。
1)<select><insert><update><delete>这几个标签很清晰的告诉我们可以在这里写什么操作。
2)parmeterType就是参数类型,可以通过id删除数据,idJ就是int型的。resultType显然就是返回值类型,就是这么简单粗暴
3)mapper的namespace属性很重要。我们是用过这个属性来找这个文件的。这个namespace和下面标签的id是一起用的,只要这样我们才能定位到具体的操作
4)还有一个隐藏问题,我的实体类和数据表的属性都是一一对应的,可是万一二者不对应怎么办。比如说 实体类是stu_id 数据表是id.很明显这会出问题,你看,我们在遍历的时候会从数据表返回信息 id ,但是我们会得到的是实体类student的对象,这才是orm嘛。可以stu_id和id不匹配,在hibernate中我们是通过对象关系映射文件来处理这个问题的,可如今这个文件被我们用来写具体的操作了,怎么办?
1] 通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致,这样就可以表的字段名和实体类的属性名一一对应上了,这种方式是通过在sql语句中定义别名来解决字段名和属性名的映射关系的。
2] 通过<resultMap>来映射字段名和实体类属性名的一一对应关系。这种方式是使用MyBatis提供的解决方式来解决字段名和属性名的映射关系的。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd" > <!-- 为这个mapper指定一个唯一的namespace,namespace的值习惯上设置成包名+sql映射文件名,这样就能够保证namespace的值是唯一的 --> <mapper namespace="com.zhao.entity.StudentMapper"> <!-- 在select标签中编写查询的SQL语句, 设置select标签的id属性为selectStudentById,id属性值必须是唯一的,不能够重复 使用parameterType属性指明查询时使用的参数类型,resultType属性指明查询返回的结果集类型 --> <select id="selectStudentById" parameterType="int" resultType="Student"> select * from Student where stu_id=#{id} </select> <select id="queryStudent" resultMap="resultQueryStudent"> select * from Student </select> <delete id="deleteStudentById" parameterType="int"> delete from Student where stu_id=#{stu_id} </delete> <!-- 以#{stu_name}的形式引用Student参数 的stu_name属性,MyBatis将使用反射读取Student参数 的此属性。#{stu_name}中stu_name大小写敏感。seGeneratedKeys设置 为"true"表明要MyBatis获取由数据库自动生成的主 键;keyProperty="id"指定把获取到的主键值注入 到Student的id属性 --> <insert id="insertStudent" parameterType="Student" useGeneratedKeys="true" keyProperty="stu_id"> insert into Student(stu_name,stu_gender) values(#{stu_name},#{stu_gender}) </insert> <update id="updateStudentById" parameterType="Student"> update Student set stu_name=#{stu_name},stu_gender=#{stu_gender} where stu_id=#{stu_id} </update> <resultMap type="Student" id="resultQueryStudent"> <id column="stu_id" property="stu_id" /> <result column="stu_name" property="stu_name" /> <result column="stu_gender" property="stu_gender" /> </resultMap> </mapper>
4:测试代码
这有个很有意思的事情,我们的事务是通过session来提交的。session.commit()。开始我写这些代码的时候怎么都没有改变数据表的信息,也就是数据没提交,我才想起来是这个问题。hibernate是通过session创建transaction来提交的。这里都让session自己把事干了。其实在写MyBatis的配置文件Configuration.xml时我就应该意识到这个问题,如果不是session提交,那我们还写事务干嘛。
MyBatis里 sqlsession的方法签名有很多,多看看,就知道下面的代码怎么写了。
package com.zhao.entity; import static org.junit.Assert.*; import java.io.FileInputStream; import java.io.InputStream; import java.io.Reader; 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.junit.Before; import org.junit.Test; import java.util.List; public class StudentTest { /* * MyBatis加载配置文件 * 1:使用类加载器加载mybatis的配置文件(它也加载关联的映射文件); * 2:使用MyBatis提供的Resources类加载mybatis的配置文件(它也加载关联的映射文件) */ private SqlSessionFactory factory; @Before public void before(){ try{ /* * 1: * Reader reader =Resources.getResourceAsReader("Configuration.xml"); * factory = new SqlSessionFactoryBuilder().build(reader); */ //2: InputStream inputStream = StudentTest.class.getClassLoader().getResourceAsStream("Configuration.xml"); factory = new SqlSessionFactoryBuilder().build(inputStream); } catch (Exception e) { e.printStackTrace(); } } @Test public void testSelectStudentById() { SqlSession session = factory.openSession(); try { Student student = (Student) session.selectOne("com.zhao.entity.StudentMapper.selectStudentById", 1); System.out.println(student); session.commit(); } finally { session.close(); } } @Test public void testQueryStudent() { SqlSession session = factory.openSession(); try { List<Student> students=session.selectList("queryStudent"); for (Student student : students) { System.out.println(student); } session.commit(); } finally { session.close(); } } @Test public void testDeleteStudentById() { SqlSession session = factory.openSession(); try { int result=session.delete("deleteStudentById",4); System.out.println(result); session.commit(); } finally { session.close(); } } @Test public void testUpdateStudentById() { SqlSession session = factory.openSession(); try { Student student=new Student(3,"zhao", "男"); session.update("updateStudentById", student); session.commit(); } finally { session.close(); } } @Test public void testInsertStudent() { SqlSession session = factory.openSession(); try { Student student=new Student("zhao", "z"); session.insert("insertStudent", student); session.commit(); } finally { session.close(); } } }