目前最常见的支持定制化 SQL、存储过程以及高级映射的优秀的数据库框架。
一、使用前准备
1.加入相关的jar包。这里使用mybatis-3.2.2.jar包,数据库使用mysql 5.5版本
2.创建mybatis的配置文件
使用的表为user,简单地描述Mybatis操作过程
CREATE TABLE `user` ( `id` int(11) NOT NULL, `username` varchar(20) DEFAULT NULL, `sex` char(2) DEFAULT NULL, `birthday` date DEFAULT NULL, `address` varchar(50) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
<?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> <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/mybatis" /> <property name="username" value="root" /> <property name="password" value="root" /> </dataSource> </environment> </environments> </configuration>
这里配置文件的参数可以提取到properties文件中,具体格式为driver=com.mysql.jdbc.Driver 同时配置文件相应位置用${driver}代替,在configuration标签下需添加properties标签,resource为属性文件地址。
3.创建映射文件,映射文件相当于dao接口的实现类
<?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"> <!-- namespace:表示名称空间。现在的目的是区分id的. --> <mapper namespace="com.zhiyou100.cyf.dao.UserDao"> <!-- 根据id查询用户。id:标识该标签。 parameterType:参数类型。可以写 也可以省略 resultType:返回结果的类型。 #{id}:类似于EL表达式。 解析id的值 --> <select id="getUser" parameterType="int" resultType="com.zhiyou100.cyf.bean.User"> select * from users where id=#{id} </select> </mapper>
映射文件和配置文件等可以放在一个新建立的源文件夹里
4.映射文件要引入到配置文件内
在configuration标签内添加
<mappers> <mapper resource="com/zhiyou100/cyf/mapper/userMapper.xml" /> </mappers>
5.加入日志:引入log4j-1.2.17.jar包,创建日志文件log4j.properties
log4j.properties,
log4j.rootLogger=DEBUG, Console
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
二、创建关系表和对应的实体类、操作接口和实现的映射文件,映射文件基本增删改查的操作略。
1.dao接口结合对应的映射文件
映射文件的namespace属性应为该接口的位置,接口的方法名与映射文件中相应的id属性值相同
三、测试
class ClazzDaoTest { static SqlSession session=null; static UserDao cd=null; @BeforeAll static void setUpBeforeClass() throws Exception { Reader reader=Resources.getResourceAsReader("conf.xml");//读取配置文件 SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(reader);//获取SqlSessionFactory对象 session=sessionFactory.openSession();//获取session,相当于jdbc中的Connection ud=session.getMapper(UserDao.class);//创建一个dao对象 } @AfterAll static void tearDownAfterClass() throws Exception { session.commit(); }
四、一些问题
1.sql字段与java属性不匹配
一种方案是给查询字段起别名,使其与java属性一致
另一种是使用resultMap标签来定义实体类与字段之间的对应关系
<select id="queryById" resultMap="userMap"> select * from user where t_id=#{id} </select> <resultMap type="com.zhiyou100.cyf.bean.User" id="teacherMap"> <id column="u_id" property="id"/> <result column="u_name" property="name"/> </resultMap>
2.连表查询
一对一或多对一:一个班有一个老师,根据班级id查询所关联的老师信息,或根据班级内的学生查询所关联的老师信息
在班级类中增加一个老师的属性
<resultMap type="com.zhiyou100.xz.bean.Clazz" id="clazzMapper"> <!-- id:标签标识表中的主键与实体类的值属性对应关系 --> <id column="c_id" property="cid"/> <result column="c_name" property="cname"/> <result column="teacher_id" property="tid"/> <!-- 该类中引入的一的一方的属性 property:属性名 javaType:该属性的Java类型 --> <association property="teacher" javaType="com.zhiyou100.cyf.bean.Teacher"> <id column="t_id" property="tid"/> <result column="t_name" property="tname"/> </association>
select中语句为连接查询语句。如果用嵌套查询,则需要另外创建并实现TeacherDao的queryById方法
<association property="teacher" javaType="com.zhiyou100.xz.bean.Teacher" column="teacher_id" select="com.zhiyou100.cyf.dao.TeacherDao.queryById"> </association>
一对多:如查询在一个班的所有学生
在班级类内创建students属性,类型为List<Student>
</association> <!-- ofType:集合中泛型的类型 --> <collection property="students" ofType="com.zhiyou100.cyf.bean.Student"> <id property="sid" column="s_id"/> <result property="sname" column="s_name"/> </collection>
在resultMap中添加collection标签,mybatis会自动给若干个student装进一个集合。同样,如果用嵌套查询,要在StudentDao中创建并实现返回list的queryByCId方法
<collection property="students" ofType="com.zhiyou100.cyf.bean.Student" column="c_id" select="com.zhiyou100.cyf.dao.StudentDao.queryByCId"></collection>
3.sql语句中$与#区别:
$: 解析时不会为内容添加””,他是sql语句的拼接存在sql注入的危害。传入的为表结构,order by排序等不需要字符串的情况下使用它。
#: 解析时会为内容添加””,它的sql时采用占位符,防止sql注入,尽量使用。
4.添加对象时如何把生产的id返回
<insert parameterType="com.zhiyou100.cyf.bean.User" userGenerateKeys="true" keyProperty="id">insert user(name,age) values(#{name},#{age})</insert>
userGenerateKeys,keyProperty两个属性必须同时使用,id返回到调用者的参数user对象的id属性上
5.测试类中update类操作的事务性
@AfterAll static void tearDownAfterClass() throws Exception { session.commit();//在代码执行完后,才使数据库执行增删改操作 }
为了保证安全和严谨,此处模拟了事务操作,一系列操作要么都执行,要么都不执行