وفقًا للبيان الرسمي، تم الانتهاء من أعمال تطوير Spring3 قبل ظهور ibatis3، أي Mybatis3، لذلك لا يوجد حتى الآن دعم لـ Mybatis3 في Spring3. لذلك، قام مجتمع Mybatis بتطوير Mybatis-Spring نفسه لتلبية احتياجات مستخدمي Mybatis لدمج Spring. فيما يلي مقدمة موجزة لاستخدام دمج Mybatis وSpring من خلال Mybatis-Spring.
MapperFactoryBean
أولاً، نحتاج إلى تنزيل حزمة Mybatis-Spring jar من موقع Mybatis الرسمي وإضافتها إلى مسار الفصل لمشروعنا. بالطبع، نحتاج أيضًا إلى إضافة حزمة jar ذات الصلة من Mybatis وحزمة Spring ذات الصلة. نحن نعلم أن جميع العمليات في Mybatis تعتمد على SqlSession، ويتم إنشاء SqlSession بواسطة SqlSessionFactory، ويتم إنشاء SqlSessionFactory بواسطة SqlSessionFactoryBuilder. لكن Mybatis-Spring يعتمد على SqlSessionFactoryBean. عند استخدام Mybatis-Spring، نحتاج أيضًا إلى SqlSession، وهذه الجلسة SqlSession مضمنة في البرنامج ولا تتطلب منا عمومًا الوصول إليها مباشرة. يتم إنشاء SqlSession أيضًا بواسطة SqlSessionFactory، لكن Mybatis-Spring يغلف SqlSessionFactoryBean لنا في هذه الحبة، ما زلنا نستخدم SqlSessionFactoryBuilder لإنشاء SqlSessionFactory المقابل، ثم نحصل على SqlSession المقابل. من خلال SqlSessionFactoryBean يمكننا توفير بعض معلومات تكوين Mybatis عن طريق تحديد بعض الخصائص عليه. لذلك نحتاج بعد ذلك إلى تحديد SqlSessionFactoryBean في ملف تكوين applicationContext الخاص بـ Spring.
كود اكس ام ال
<bean id = "sqlSessionFactory"> <property name = "dataSource" ref = "dataSource" /> <property name = "mapperLocations" value = "classpath:com/tiantian/ckeditor/mybatis/mappers/*Mapper.xml" / > <property name="typeAliasesPackage" value="com.tiantian.ckeditor.model" /> </bean>
عند تعريف SqlSessionFactoryBean، يجب تحديد سمة مصدر البيانات، والتي تمثل مصدر البيانات المستخدم للاتصال بقاعدة البيانات. بالطبع، يمكننا أيضًا تحديد بعض السمات الأخرى، فيما يلي بعض منها:
MapperLocations: يشير إلى الموقع الذي يتم فيه تخزين ملف Mapper الخاص بنا. عندما يكون ملف Mapper الخاص بنا في نفس موقع واجهة Mapper المقابلة، ليست هناك حاجة لتحديد قيمة هذه السمة.
configLocation: يستخدم لتحديد موقع ملف التكوين لـ Mybatis. إذا تم تحديد هذه السمة، فسيتم إنشاء SqlSessionFactoryBuilder المقابل باستخدام محتوى ملف التكوين كمعلومات التكوين، ولكن المحتوى المحدد بواسطة السمات اللاحقة سوف يحل محل المحتوى المقابل المحدد في ملف التكوين.
typeAliasesPackage: يتوافق بشكل عام مع الحزمة التي توجد بها فئة الكيان الخاصة بنا. في هذا الوقت، سيتم تلقائيًا اعتبار اسم الفئة البسيط في الحزمة المقابلة، والذي لا يتضمن اسم الحزمة، كاسم مستعار بما في ذلك اسم الحزمة. يمكن فصل الحزم المتعددة بفواصل أو فواصل منقوطة.
typeAliases: نوع الصفيف، يستخدم لتحديد الأسماء المستعارة. بعد تحديد هذه السمة، سيستخدم Mybatis الاسم المختصر لهذا النوع كاسم مستعار لهذا النوع، بشرط ألا يتم وضع علامة على التعليق التوضيحي @Alias في الفئة، وإلا سيتم استخدام القيمة المقابلة للتعليق التوضيحي كاسم مستعار لـ هذا النوع.
كود اكس ام ال
<property name="typeAliases"> <array> <value>com.tiantian.mybatis.model.Blog</value> <value>com.tiantian.mybatis.model.Comment</value> </array> </property >
المكونات الإضافية: نوع الصفيف، يستخدم لتحديد اعتراض Mybatis.
typeHandlersPackage: يُستخدم لتحديد الحزمة التي يوجد بها TypeHandler، إذا تم تحديد هذه السمة، فسيقوم SqlSessionFactoryBean تلقائيًا بتسجيل الفئات ضمن الحزمة باعتبارها TypeHandler المقابلة. يمكن فصل الحزم المتعددة بفواصل أو فواصل منقوطة.
typeHandlers: نوع الصفيف، الذي يمثل TypeHandler.
الخطوة التالية هي تحديد MapperFactoryBean المطابق لكائن Mapper الذي نريده في ملف applicationContext الخاص بـ Spring. يمكن الحصول على كائن Mapper الذي نريده من خلال MapperFactoryBean. يطبق MapperFactoryBean واجهة Spring's FactoryBean، لذلك يحصل MapperFactoryBean على كائن Mapper المقابل من خلال طريقة getObject المحددة في واجهة FactoryBean. عند تحديد MapperFactoryBean، هناك خاصيتان نحتاج إلى إدخالهما. إحداهما هي sqlSessionFactory التي يستخدمها Mybatis-Spring لإنشاء كائنات SqlSessionTemplate التي تنفذ واجهة SqlSession، والأخرى هي واجهة Mapper المقابلة التي نريد إرجاعها.
بعد تحديد MapperFactoryBean المطابق لواجهة Mapper المقابلة، يمكننا حقن واجهة Mapper المقابلة لدينا في كائن الفول الذي يديره Spring، مثل كائن حبة الخدمة. بهذه الطريقة، عندما نحتاج إلى استخدام واجهة Mapper المقابلة، سيحصل MapperFactoryBean على واجهة Mapper المقابلة من طريقة getObject الخاصة به، ولا يزال getObject داخليًا يستدعي طريقة getMapper (واجهة Mapper) لواجهة SqlSession من خلال الخصائص التي أدخلناها لإرجاع واجهة مخطط المقابلة. بهذه الطريقة، يتم تحقيق تكامل Mybatis وSpring من خلال تسليم SqlSessionFactory وواجهة Mapper المقابلة لإدارة Spring.
ملف التكوين applicationContext.xml الخاص بـ Spring:
كود اكس ام ال
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org /2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc = "http://www.springframework.org/schema/mvc" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans /spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring- mvc-3.0.xsd"> <context:component-scan base-package="com.tiantian.mybatis"/> <context:property-placeholder location="classpath:config/jdbc.properties"/> <bean id="dataSource" Destroy-method="Close"> <property name="driverClassName" value="${jdbc.driver}" /> <اسم الخاصية ="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <bean id="sqlSessionFactory"> <property name="dataSource" ref="dataSource" /> <property name="mapperLocations" value="classpath: com/tiantian/mybatis/mapper/*.xml"/> <property name="typeAliasesPackage" value="com.tiantian.mybatis.model" /> </bean> <bean id="blogMapper"> <property name="mapperInterface" value="com.tiantian.mybatis.mapper.BlogMapper" /> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </ فاصوليا> فاصوليا> </فاصوليا>
ملف BlogMapper.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="com.tiantian.mybatis.mapper.BlogMapper"> <!-- إضافة سجل جديد--> <insert id="insertBlog" ParameterType="Blog" useGeneratedKeys="true" keyProperty="id"> أدخل في قيم t_blog(title,content,owner)(#{title},#{content},#{owner}) </ إدراج> <!-- الاستعلام عن سجل واحد--> <select id="selectBlog" ParameterType="int" resultMap="BlogResult"> حدد * من t_blog حيث id = #{id} </select> <!-- تعديل السجل--> <update id="updateBlog" ParameterType="Blog"> تحديث t_blog set title = #{title},content = #{content},owner = #{owner} حيث id = #{id} </update> <!-- الاستعلام عن جميع السجلات--> <select id="selectAll" resultType="Blog"> حدد * من t_blog </select> <!-- حذف السجلات--> <delete id="deleteBlog" بارامتراتType="int"> احذف من t_blog حيث المعرف = #{id} </delete> </mapper>
BlogMapper.java:
كود جافا
package com.tiantian.mybatis.mapper; import java.util.List; import com.tiantian.mybatis.model.Blog; publicinterface تحديدBlog(int id); ); publicvoiddeleteBlog(int id);
BlogServiceImpl.java:
كود جافا
package com.tiantian.mybatis.service.impl; import java.util.List; import javax.annotation.Resource; import org.springframework.stereotype.Service; import com.tiantian.mybatis.mapper.BlogMapper; mybatis.model.Blog; import com.tiantian.mybatis.service.BlogService; BlogMapper blogMapper; publicvoiddeleteBlog(int id) { blogMapper.deleteBlog(id); publicvoid InsertBlog(Blog blog) { blogMapper.insertBlog(blog } publicvoid updateBlog(Blog blog) { blogMapper.updateBlog(blog); } public BlogMapper getBlogMapper() { returnblogMapper } @Resource publicvoid setBlogMapper(BlogMapper blogMapper) { this.blogMapper = blogMapper } }
MapperScannerConfigurer
عند استخدام الطريقة المذكورة أعلاه للتكامل، إذا كان لدينا مصمم خرائط، فسنحتاج إلى تحديد MapperFactoryBean المقابل. عندما يكون لدينا عدد قليل نسبيًا من مصممي الخرائط، فلا بأس بذلك، ولكن عندما يكون لدينا عدد كبير جدًا من مصممي الخرائط، فإننا نحدد كل مخطط على النحو التالي: يبدو أن MapperFactoryBean المقابل أبطأ. لهذا الغرض، يوفر لنا Mybatis-Spring فئة تسمى MapperScannerConfigurer. من خلال هذه الفئة، سيقوم Mybatis-Spring تلقائيًا بتسجيل كائن MapperFactoryBean المطابق لـ Mapper.
إذا كنا بحاجة إلى استخدام MapperScannerConfigurer لمساعدتنا في مسح واجهة Mapper وتسجيلها تلقائيًا، فسنحتاج إلى تحديد وحدة الفول المقابلة لـ MapperScannerConfigurer في ملف تكوين applicationContext الخاص بـ Spring. بالنسبة لـ MapperScannerConfigurer، هناك سمة واحدة يجب أن نحددها، وهي basePackage. يتم استخدام basePackage لتحديد الحزمة الأساسية التي يوجد بها ملف واجهة Mapper، وسيتم البحث في واجهات Mapper ضمن هذه الحزمة الأساسية أو جميع حزمها الفرعية. يمكن فصل الحزم الأساسية المتعددة بفواصل أو فواصل منقوطة. إن أبسط تعريف لـ MapperScannerConfigurer هو تحديد سمة حزمة أساسية واحدة فقط، مثل:
كود اكس ام ال
<bean> <property name="basePackage" value="com.tiantian.mybatis.mapper" /> </bean>
بهذه الطريقة، سيقوم MapperScannerConfigurer بفحص جميع الواجهات ضمن الحزمة الأساسية المحددة وتسجيلها ككائنات MapperFactoryBean. عند استخدام MapperScannerConfigurer وإضافة سمة basePackage، سيصبح ملف تكوين applicationContext في مثالنا أعلاه كما يلي:
كود اكس ام ال
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org /2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc = "http://www.springframework.org/schema/mvc" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans /spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring- mvc-3.0.xsd"> <context:component-scan base-package="com.tiantian.mybatis" /> <context:property-placeholder location="classpath:config/jdbc.properties" /> <bean id="dataSource" Destroy-method="Close"> <property name="driverClassName" value="${jdbc.driver}" /> <اسم الخاصية ="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <bean id="sqlSessionFactory"> <property name="dataSource" ref="dataSource" /> <property name="mapperLocations" value="classpath: com/tiantian/mybatis/mapper/*.xml" /> <property name="typeAliasesPackage" value="com.tiantian.mybatis.model" /> </bean> <bean> <property name="basePackage" value="com.tiantian.mybatis.mapper" /> </bean> </beans>
في بعض الأحيان، لا تكون الحزمة الأساسية التي نحددها جميع واجهات Mapper التي حددناها. ولهذا السبب، يوفر لنا MapperScannerConfigurer أيضًا سمتين أخريين يمكنهما تضييق نطاق البحث والتسجيل. أحدهما هو annotationClass والآخر هو MarkerInterface.
annotationClass: عند تحديد annotationClass، سيقوم MapperScannerConfigurer بتسجيل الواجهات المميزة فقط بالتعليق التوضيحي annotationClass.
MarkerInterface: يتم استخدام MarkerInterface لتحديد واجهة. عند تحديد MarkerInterface، سيقوم MapperScannerConfigurer بتسجيل الواجهة الموروثة من markInterface فقط.
إذا تم تحديد كلا الخاصيتين أعلاه، فسيأخذ MapperScannerConfigurer اتحادهما بدلاً من تقاطعهما. حتى إذا تم استخدام annotationClass لوضع العلامات أو سيتم تسجيل الواجهة الموروثة من MarkerInterface على أنها MapperFactoryBean.
الآن بافتراض أن واجهة Mapper لدينا ترث واجهة SuperMapper، فيمكننا تعريف MapperScannerConfigurer الخاص بنا مثل هذا.
كود اكس ام ال
<bean> <property name = "basePackage" value = "com.tiantian.mybatis.mapper" /> <property name = "markerInterface" value = "com.tiantian.mybatis.mapper.SuperMapper"/> </bean>
إذا تم استخدام علامة التعليق التوضيحي MybatisMapper، فيمكننا تحديد MapperScannerConfigurer الخاص بنا مثل هذا.
كود اكس ام ال
<bean> <property name = "basePackage" value = "com.tiantian.mybatis.mapper" /> <property name = "annotationClass" value = "com.tiantian.mybatis.annotation.MybatisMapper"/> </bean>
بالإضافة إلى الخصائص المستخدمة لتضييق نطاق واجهة Mapper المسجلة، يمكننا أيضًا تحديد بعض الخصائص الأخرى، مثل:
sqlSessionFactory: تم إهمال هذه الخاصية. عندما نستخدم مصادر بيانات متعددة، نحتاج إلى استخدام sqlSessionFactory لتحديد SqlSessionFactory الذي يجب استخدامه عند تسجيل MapperFactoryBean، لأنه عندما لا يتم تحديد sqlSessionFactory، سيتم إدخاله تلقائيًا بطريقة Autowired. بمعنى آخر، عندما نستخدم مصدر بيانات واحدًا فقط، أي عندما نحدد SqlSessionFactory واحدًا فقط، لا نحتاج إلى تحديد SqlSessionFactory لـ MapperScannerConfigurer.
sqlSessionFactoryBeanName: وظيفتها هي نفس وظيفة sqlSessionFactory، باستثناء أنها تحدد اسم الفول المطابق لـ SqlSessionFactory المحدد.
sqlSessionTemplate: تم إهمال هذه السمة. وظيفتها تعادل أيضًا sqlSessionFactory، لأنه كما ذكرنا سابقًا، يستخدم MapperFactoryBean في النهاية طريقة getMapper الخاصة بـ SqlSession للحصول على كائن Mapper المقابل. يجب تحديده فقط عند تحديد قوالب SqlSessionTemplates متعددة. بالنسبة إلى MapperFactoryBean، يلزم وجود واحد فقط من SqlSessionFactory وSqlSessionTemplate. عند تحديد كليهما، سيتم تجاهل SqlSessionFactory.
sqlSessionTemplateBeanName: حدد اسم الفول المطابق لـ sqlSessionTemplate المراد استخدامه.
ملاحظة: نظرًا لأن استخدام سمات sqlSessionFactory وsqlSessionTemplate سيؤدي إلى تحميل بعض المحتوى قبل PropertyPlaceholderConfigurer، فلا يمكن استبدال معلومات الخاصية الخارجية المستخدمة في ملف التكوين في الوقت المناسب وستحدث أخطاء رسمية تم التخلي عن خصائص sqlSessionFactory وsqlSessionTemplate في Mybatis-Spring، ويوصى باستخدام خاصية sqlSessionFactoryBeanName وخاصية sqlSessionTemplateBeanName.
كود اكس ام ال
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org /2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc = "http://www.springframework.org/schema/mvc" xmlns:mybatis = "http://www.mybatis.org/schema/mybatis" xsi:schemaLocation = "http://www.springframework .org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.mybatis.org/schema/mybatis http:/ /www.mybatis.org/schema/mybatis/mybatis-spring.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> <context:component-scan base-package="com.tiantian.mybatis" /> <context:property-placeholder location= "classpath:config/jdbc.properties" /> <bean id = "dataSource" Destroy-method = "Close"> <property name = "driverClassName" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <bean id="sqlSessionFactory"> <property name="dataSource" ref="dataSource" /> <property name="mapperLocations" value="classpath:com/tiantian/mybatis/mapper/*.xml" /> <property name="typeAliasesPackage" value="com.tiantian.mybatis.model" /> </bean> <bean> <property name = "basePackage" value = "com.tiantian.mybatis.mapper" /> <property name = "markerInterface" value="com.tiantian.mybatis.mapper.SuperMapper"/> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> </bean> </beans>
SqlSessionTemplate
بالإضافة إلى استخدام واجهة Mapper مباشرة بعد التكامل أعلاه، يوفر لنا Mybatis-Spring أيضًا طريقة لاستخدام SqlSession مباشرة. يوفر لنا Mybatis-Spring فئة SqlSessionTemplate التي تنفذ واجهة SqlSession، وهي آمنة للخيوط ويمكن استخدامها من قبل Dao متعددة في نفس الوقت. وفي الوقت نفسه، يتم ربطه أيضًا بمعاملة Spring للتأكد من أن جلسة SqlSession المستخدمة حاليًا هي تلك المرتبطة بمعاملة Spring. ويمكنه أيضًا إدارة تقديم الجلسة وإغلاقها بنفسه. عند استخدام آلية إدارة المعاملات الخاصة بـ Spring، يمكن أيضًا إرسال SqlSession وإعادتها مع معاملات Spring.
عند استخدام SqlSessionTemplate يمكننا تعريفه في ملف تكوين applicationContext الخاص بـ Spring كما يلي:
<bean id="sqlSession"> <constructor-arg Index="0" ref="sqlSessionFactory" /> </bean>
بهذه الطريقة، يمكننا استخدام SqlSessionTemplate مباشرةً للبرمجة في Dao من خلال حقن تبعية Spring. في هذا الوقت، قد يبدو Dao الخاص بنا كما يلي:
كود جافا
package com.tiantian.mybatis.dao; import java.util.List; import javax.annotation.Resource; import org.mybatis.spring.SqlSessionTemplate; import org.springframework.stereotype.Repository; Blog; @Repository publicclass BlogDaoImpl Implements BlogDao { Private SqlSessionTemplate sqlSessionTemplate; publicvoiddeleteBlog(int id) { sqlSessionTemplate.delete("com.tiantian.mybatis.mapper.BlogMapper.deleteBlog", id); public Blog find(int id) { returnqlSessionTemplate.selectOne("com.tiantian.mybatis. Mapper.BlogMapper.selectBlog"، id); } public List<Blog> find() { returnthis.sqlSessionTemplate.selectList("com.tiantian.mybatis.mapper.BlogMapper.selectAll"); } publicvoid InsertBlog(Blog blog) { this.sqlSessionTemplate.insert("com.tiantian. mybatis.mapper.BlogMapper.insertBlog"، blog); } publicvoid updateBlog(Blog blog) { this.sqlSessionTemplate.update("com.tiantian.mybatis.mapper.BlogMapper.updateBlog"، blog); } public SqlSessionTemplate getSqlSessionTemplate() { returnqlSessionTemplate } @Resource publicvoid setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) { this.sqlSessionTemplate = sqlSessionTemplate; } }
ملحوظة:
تمت كتابة هذه المقالة استنادًا إلى Mybatis3.2.1 وMybatis-Spring1.1.0 وSpring3.1.
ما ورد أعلاه هو تحليل موجز لعملية تنفيذ تكامل Mybatis وSpring المقدمة في هذه المقالة، وآمل أن ينال إعجابك. ستقدم لك المقالة التالية طريقة تكامل Spring وMybatis.